1use crate::code_bld::CodeBuilder;
7use crate::ctx::Context;
8use crate::{FlagState, FlagStateKind};
9use source_map_node::Node;
10use swamp_semantic::{
11 BinaryOperator, BinaryOperatorKind, BooleanExpression, Expression, ExpressionKind,
12 UnaryOperator, UnaryOperatorKind,
13};
14use swamp_types::TypeKind;
15use swamp_vm_types::PatchPosition;
16use swamp_vm_types::types::{Place, TypedRegister, VmType, b8_type};
17
18impl CodeBuilder<'_> {
19 pub(crate) fn force_normalized_bool_reg_if_needed(
20 &mut self,
21 target: &TypedRegister,
22 t_flag_state: FlagState,
23 node: &Node,
24 ) {
25 match t_flag_state.kind {
26 FlagStateKind::TFlagIsIndeterminate => {
27 }
29 FlagStateKind::TFlagIsTrueWhenSet => {
30 }
33 FlagStateKind::TFlagIsTrueWhenClear => {
34 self.builder
35 .add_meqz(target, target, node, "materialize inverse boolean");
36 }
37 }
38 }
39 pub fn emit_unary_operator_logical(
40 &mut self,
41 dest_bool_reg: &TypedRegister,
42 unary_operator: &UnaryOperator,
43 ctx: &Context,
44 ) -> FlagState {
45 match &unary_operator.kind {
46 UnaryOperatorKind::Not => match &*unary_operator.left.ty.kind {
47 TypeKind::Bool => {
48 let bool_result =
49 self.emit_expression_to_boolean(dest_bool_reg, &unary_operator.left, ctx);
50 bool_result.invert_polarity()
51 }
52 _ => panic!("unknown not"),
53 },
54 _ => panic!("unary operator do not provide P flag"),
55 }
56 }
57
58 pub(crate) fn emit_condition_context(
59 &mut self,
60 condition: &BooleanExpression,
61 ctx: &Context,
62 ) -> PatchPosition {
63 let hwm = self.temp_registers.save_mark();
64 let temp_truth_reg = self.temp_registers.allocate(
65 VmType::new_contained_in_register(b8_type()),
66 "true-register for condition",
67 );
68 let result =
69 self.emit_expression_to_boolean(temp_truth_reg.register(), &condition.expression, ctx);
70
71 let patch = self.builder.add_jmp_if_not_equal_polarity_placeholder(
72 temp_truth_reg.register(),
73 &result.polarity(),
74 &condition.expression.node,
75 "jump boolean condition false",
76 );
77
78 self.temp_registers.restore_to_mark(hwm);
79
80 patch
81 }
82
83 pub(crate) fn emit_expression_to_boolean(
84 &mut self,
85 dest_bool_reg: &TypedRegister,
86 condition: &Expression,
87 ctx: &Context,
88 ) -> FlagState {
89 match &condition.kind {
90 ExpressionKind::CoerceOptionToBool(option_union_expr) => {
91 let region = self.emit_scalar_rvalue(option_union_expr, ctx);
92
93 let tag_reg = self.temp_registers.allocate(
94 VmType::new_unknown_placement(swamp_vm_types::types::b8_type()),
95 "temp for option tag",
96 );
97
98 let (tag_offset, ..) = region.ty.basic_type.unwrap_info().unwrap();
99 self.builder.add_ld8_from_pointer_with_offset(
100 tag_reg.register(),
101 ®ion,
102 tag_offset,
103 &option_union_expr.node,
104 "load option tag",
105 );
106
107 self.builder.add_mov_reg(
108 dest_bool_reg,
109 tag_reg.register(),
110 &option_union_expr.node,
111 "test option tag",
112 );
113
114 return FlagState {
115 kind: FlagStateKind::TFlagIsTrueWhenSet,
116 };
117 }
118 ExpressionKind::BinaryOp(operator) => match &operator.kind {
119 BinaryOperatorKind::LogicalAnd | BinaryOperatorKind::LogicalOr => {
120 return self.emit_binary_operator_logical_to_boolean(
121 dest_bool_reg,
122 operator,
123 ctx,
124 );
125 }
126 BinaryOperatorKind::Equal | BinaryOperatorKind::NotEqual => {
127 let left = self.emit_scalar_rvalue(&operator.left, ctx);
128 let right = self.emit_scalar_rvalue(&operator.right, ctx);
129 let is_equal_polarity = matches!(operator.kind, BinaryOperatorKind::Equal);
130 return self.emit_equality_to_bool_target(
131 dest_bool_reg,
132 &left,
133 is_equal_polarity,
134 &right,
135 &operator.node,
136 ctx,
137 );
138 }
139 BinaryOperatorKind::GreaterEqual
140 | BinaryOperatorKind::GreaterThan
141 | BinaryOperatorKind::LessThan
142 | BinaryOperatorKind::LessEqual => {
143 let left_source = self.emit_scalar_rvalue(&operator.left, ctx);
144 let right_source = self.emit_scalar_rvalue(&operator.right, ctx);
145
146 return self.emit_binary_operator_relational(
147 dest_bool_reg,
148 &left_source,
149 operator,
150 &right_source,
151 );
152 }
153 _ => panic!(
154 "binary operator does not provide us with P flag {:?}",
155 condition.kind
156 ),
157 },
158 ExpressionKind::UnaryOp(operator) => match &operator.kind {
159 UnaryOperatorKind::Not => {
160 return self.emit_unary_operator_logical(dest_bool_reg, operator, ctx);
161 }
162 _ => panic!("unary operator does not provide us with P flag"),
163 },
164 _ => {
165 let destination = Place::Register(dest_bool_reg.clone());
166 self.emit_expression(&destination, condition, ctx);
167 }
168 }
169
170 FlagState {
171 kind: FlagStateKind::TFlagIsTrueWhenSet,
172 }
173 }
174
175 fn emit_expression_to_normalized_t_flag(
176 &mut self,
177 dest_bool_reg: &TypedRegister,
178 condition: &Expression,
179 ctx: &Context,
180 ) {
181 let result = self.emit_expression_to_boolean(dest_bool_reg, condition, ctx);
182 assert_ne!(result.kind, FlagStateKind::TFlagIsIndeterminate);
183
184 if result.kind == FlagStateKind::TFlagIsTrueWhenClear {
185 self.builder.add_meqz(
186 dest_bool_reg,
187 dest_bool_reg,
188 &condition.node,
189 "normalized z is required",
190 );
191 }
192 }
193 pub(crate) fn emit_binary_operator_logical_to_boolean(
194 &mut self,
195 dest_bool_reg: &TypedRegister,
196 binary_operator: &BinaryOperator,
197 context: &Context,
198 ) -> FlagState {
199 let node = &binary_operator.node;
200
201 let kind = FlagStateKind::TFlagIsTrueWhenSet;
203
204 match binary_operator.kind {
205 BinaryOperatorKind::LogicalOr => {
206 self.emit_expression_to_normalized_t_flag(
207 dest_bool_reg,
208 &binary_operator.left,
209 context,
210 );
211
212 let jump_after_patch = self.builder.add_jmp_if_true_placeholder(
213 dest_bool_reg,
214 node,
215 "OR: skip rhs because lhs is true",
216 );
217
218 self.emit_expression_to_normalized_t_flag(
219 dest_bool_reg,
220 &binary_operator.right,
221 context,
222 );
223
224 self.builder.patch_jump_here(jump_after_patch);
225 }
226 BinaryOperatorKind::LogicalAnd => {
227 self.emit_expression_to_normalized_t_flag(
228 dest_bool_reg,
229 &binary_operator.left,
230 context,
231 );
232
233 let jump_after_patch = self.builder.add_jmp_if_not_true_placeholder(
234 dest_bool_reg,
235 node,
236 "AND: skip rhs because lhs is false",
237 );
238
239 self.emit_expression_to_normalized_t_flag(
240 dest_bool_reg,
241 &binary_operator.right,
242 context,
243 );
244
245 self.builder.patch_jump_here(jump_after_patch);
246 }
247
248 _ => {
249 panic!("unknown operator {binary_operator:?}");
250 }
251 }
252
253 FlagState { kind }
254 }
255}