1use rucc_target::TargetInfo;
41use rucc_types::{TypeId, TypeKind, Types, is_arithmetic, is_pointer, is_void};
42
43use crate::expr::{Category, Conversion, Expr, ExprId, ExprKind};
44use crate::tast::{Const, Tast};
45
46#[derive(Debug)]
52pub struct Conv<'a> {
53 pub tast: &'a mut Tast,
55 pub types: &'a mut Types,
57 pub target: &'a TargetInfo,
59}
60
61impl Conv<'_> {
62 pub fn value(&mut self, expr: ExprId) -> ExprId {
68 let ty = self.tast[expr].ty;
69 match self.types.kind(self.types.canonical(ty)) {
70 TypeKind::Array { elem, .. } => {
71 let ty = self.types.pointer(elem);
72 self.write(Conversion::ArrayDecay, expr, ty)
73 }
74 TypeKind::Function(_) => {
75 let ty = self.types.pointer(ty);
76 self.write(Conversion::FunctionDecay, expr, ty)
77 }
78 _ if self.tast[expr].category == Category::Rvalue => expr,
79 _ => {
80 let ty = self.read_as(ty);
81 self.write(Conversion::Lvalue, expr, ty)
82 }
83 }
84 }
85
86 pub fn promote(&mut self, expr: ExprId) -> ExprId {
93 let expr = self.value_promoting_bits(expr);
94 let ty = self.tast[expr].ty;
95 let promoted = rucc_types::promote(self.types, ty, self.target);
96 self.arithmetic(expr, promoted)
97 }
98
99 pub fn promote_bits(&mut self, expr: ExprId, width: u32) -> ExprId {
105 let expr = self.value(expr);
106 let ty = self.tast[expr].ty;
107 let promoted = rucc_types::promote_bit_field(self.types, ty, width, self.target);
108 self.arithmetic(expr, promoted)
109 }
110
111 fn value_promoting_bits(&mut self, expr: ExprId) -> ExprId {
118 match self.bit_field_width(expr) {
119 Some(width) => self.promote_bits(expr, width),
120 None => self.value(expr),
121 }
122 }
123
124 fn bit_field_width(&self, expr: ExprId) -> Option<u32> {
134 let expr = match self.tast[expr].kind {
135 ExprKind::Convert { kind: Conversion::Lvalue, operand } => operand,
136 _ => expr,
137 };
138 let ExprKind::Member { base, field } = self.tast[expr].kind else { return None };
139 let base = self.types.canonical(self.tast[base].ty);
140 let TypeKind::Record(record) = self.types.kind(base) else { return None };
141 self.types.record_info(record).fields.get(field as usize)?.bits
142 }
143
144 pub fn usual_arithmetic(&mut self, lhs: ExprId, rhs: ExprId) -> Option<(ExprId, ExprId)> {
149 let (lhs, rhs) = (self.value_promoting_bits(lhs), self.value_promoting_bits(rhs));
150 let common = rucc_types::usual_arithmetic(
151 self.types,
152 self.tast[lhs].ty,
153 self.tast[rhs].ty,
154 self.target,
155 )?;
156 Some((self.arithmetic(lhs, common), self.arithmetic(rhs, common)))
157 }
158
159 pub fn to_bool(&mut self, expr: ExprId) -> ExprId {
165 let expr = self.value(expr);
166 let boolean = self.types.boolean();
167 if self.tast[expr].ty == boolean {
168 return expr;
169 }
170 self.write(Conversion::Bool, expr, boolean)
171 }
172
173 pub fn to_void(&mut self, expr: ExprId) -> ExprId {
180 if is_void(self.types, self.tast[expr].ty) {
181 return expr;
182 }
183 let void = self.types.void();
184 self.write(Conversion::Void, expr, void)
185 }
186
187 pub fn to_type(&mut self, expr: ExprId, ty: TypeId) -> ExprId {
194 let expr = self.value(expr);
195 let from = self.tast[expr].ty;
196 let target = self.read_as(ty);
197 if from == target {
198 return expr;
199 }
200 if is_void(self.types, target) {
201 return self.to_void(expr);
202 }
203 let boolean = self.types.boolean();
204 if target == boolean {
205 return self.to_bool(expr);
206 }
207 let kind = if is_pointer(self.types, target) {
208 if self.is_null_pointer_constant(expr) {
212 Conversion::NullPointer
213 } else {
214 Conversion::Pointer
215 }
216 } else if is_arithmetic(self.types, target) && is_arithmetic(self.types, from) {
217 Conversion::Arithmetic
218 } else if rucc_types::is_vector(self.types, target) && is_arithmetic(self.types, from) {
219 Conversion::Broadcast
220 } else {
221 Conversion::Pointer
225 };
226 self.write(kind, expr, target)
227 }
228
229 #[must_use]
235 pub fn is_null_pointer_constant(&self, expr: ExprId) -> bool {
236 match self.tast[expr].kind {
237 ExprKind::Const(value) => self.tast[value] == Const::Int(0),
238 ExprKind::Cast(inner) | ExprKind::Convert { operand: inner, .. } => {
239 self.is_null_pointer_constant(inner)
240 }
241 _ => false,
242 }
243 }
244
245 fn arithmetic(&mut self, expr: ExprId, ty: TypeId) -> ExprId {
247 if self.tast[expr].ty == ty {
248 return expr;
249 }
250 self.write(Conversion::Arithmetic, expr, ty)
251 }
252
253 pub(crate) fn read_as(&mut self, ty: TypeId) -> TypeId {
258 let stripped = match self.types.kind(self.types.canonical(ty)) {
259 TypeKind::Atomic(inner) => inner,
260 _ => ty,
261 };
262 self.types.unqualified(stripped)
263 }
264
265 fn write(&mut self, kind: Conversion, operand: ExprId, ty: TypeId) -> ExprId {
267 let span = self.tast.expr_span(operand);
268 let node = Expr::new(ExprKind::Convert { kind, operand }, ty, Category::Rvalue);
269 self.tast.expr(node, span)
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use rucc_base::Interner;
276 use rucc_diag::Span;
277 use rucc_target::{TargetInfo, Triple};
278 use rucc_types::{ArrayLen, FunctionType, IntKind, Qualifiers};
279
280 use super::*;
281 use crate::decl::{Decl, DeclKind, DeclList, Definition, Emission, Linkage, StorageDuration};
282 use crate::print::Printer;
283
284 struct Fixture {
285 tast: Tast,
286 types: Types,
287 names: Interner,
288 target: TargetInfo,
289 }
290
291 impl Fixture {
292 fn new() -> Fixture {
293 let target =
294 TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().expect("a triple"));
295 Fixture { tast: Tast::new(), types: Types::new(), names: Interner::new(), target }
296 }
297
298 fn conv(&mut self) -> Conv<'_> {
299 Conv { tast: &mut self.tast, types: &mut self.types, target: &self.target }
300 }
301
302 fn object(&mut self, ty: TypeId) -> ExprId {
304 let decl = self.tast.decl(
305 Decl {
306 name: None,
307 ty,
308 kind: DeclKind::Object,
309 linkage: Linkage::None,
310 duration: StorageDuration::Automatic,
311 state: Definition::Defined,
312 alignment: None,
313 constant: false,
314 retained: false,
315 asm_label: None,
316 alias: None,
317 inline: Emission::Silent,
318 gnu_inline: false,
319 noreturn: false,
320 visibility: None,
321 init: None,
322 params: DeclList::EMPTY,
323 body: None,
324 },
325 Span::DUMMY,
326 );
327 self.tast.expr(Expr::new(ExprKind::Decl(decl), ty, Category::Lvalue), Span::DUMMY)
328 }
329
330 fn bit_field(&mut self, ty: TypeId, bits: u32) -> ExprId {
332 let fields = [rucc_types::FieldDecl::bit_field(None, ty, bits)];
333 let id = self.types.declare_record(rucc_types::RecordKind::Struct, None);
334 let laid_out = rucc_types::layout_record(
335 &self.types,
336 rucc_types::RecordKind::Struct,
337 &fields,
338 &rucc_types::RecordOptions::default(),
339 &self.target,
340 )
341 .expect("a layout");
342 self.types.complete_record(id, laid_out);
343 let record = self.types.record(id);
344 let base = self.object(record);
345 self.tast.expr(
346 Expr::new(ExprKind::Member { base, field: 0 }, ty, Category::Bitfield),
347 Span::DUMMY,
348 )
349 }
350
351 fn zero(&mut self, ty: TypeId) -> ExprId {
352 let value = self.tast.add_const(Const::Int(0));
353 self.tast.expr(Expr::new(ExprKind::Const(value), ty, Category::Rvalue), Span::DUMMY)
354 }
355
356 fn text(&self, expr: ExprId) -> String {
357 let mut printer = Printer::new(&self.tast, &self.types, &self.names);
358 printer.expr(expr);
359 printer.finish()
360 }
361 }
362
363 #[test]
364 fn reading_an_object_drops_the_qualifiers_because_they_are_not_part_of_a_value() {
365 let mut f = Fixture::new();
366 let int = f.types.int(IntKind::Int);
367 let constant = f.types.qualified(int, Qualifiers::CONST);
368 let object = f.object(constant);
369 let read = f.conv().value(object);
370
371 assert_eq!(f.tast[read].ty, int);
372 assert_eq!(f.tast[read].category, Category::Rvalue);
373 assert_eq!(f.text(read), "convert lvalue : int\n decl #0 : const int lvalue\n");
374 }
375
376 #[test]
377 fn an_atomic_object_reads_as_the_type_it_wraps() {
378 let mut f = Fixture::new();
379 let int = f.types.int(IntKind::Int);
380 let atomic = f.types.atomic(int);
381 let object = f.object(atomic);
382 let read = f.conv().value(object);
383
384 assert_eq!(f.tast[read].ty, int);
385 }
386
387 #[test]
388 fn an_array_decays_and_is_not_read() {
389 let mut f = Fixture::new();
390 let int = f.types.int(IntKind::Int);
391 let array = f.types.array(int, ArrayLen::Fixed(3));
392 let object = f.object(array);
393 let decayed = f.conv().value(object);
394
395 assert_eq!(f.text(decayed), "convert array-decay : int *\n decl #0 : int[3] lvalue\n");
398 }
399
400 #[test]
401 fn a_function_decays_to_a_pointer_to_itself() {
402 let mut f = Fixture::new();
403 let void = f.types.void();
404 let signature =
405 FunctionType { ret: void, params: Vec::new(), variadic: false, prototyped: true };
406 let function = f.types.function(signature);
407 let designator =
408 f.tast.expr(Expr::new(ExprKind::Error, function, Category::Function), Span::DUMMY);
409 let decayed = f.conv().value(designator);
410
411 assert_eq!(
412 f.text(decayed),
413 "convert function-decay : void (*)(void)\n error : void(void) function\n"
414 );
415 }
416
417 #[test]
418 fn a_narrow_integer_promotes_and_an_int_does_not_move() {
419 let mut f = Fixture::new();
420 let char_type = f.types.int(IntKind::Char);
421 let int = f.types.int(IntKind::Int);
422 let narrow = f.object(char_type);
423 let wide = f.object(int);
424
425 let promoted = f.conv().promote(narrow);
426 assert_eq!(f.tast[promoted].ty, int);
427 assert_eq!(
428 f.text(promoted),
429 "convert arithmetic : int\n convert lvalue : char\n decl #0 : char lvalue\n"
430 );
431
432 let already = f.conv().promote(wide);
434 assert_eq!(f.text(already), "convert lvalue : int\n decl #1 : int lvalue\n");
435 }
436
437 #[test]
438 fn a_bit_field_promotes_by_its_width_and_not_by_its_type() {
439 let mut f = Fixture::new();
440 let unsigned = f.types.int(IntKind::UInt);
441 let int = f.types.int(IntKind::Int);
442 let three = f.object(unsigned);
443 let full = f.object(unsigned);
444
445 let narrow = f.conv().promote_bits(three, 3);
447 assert_eq!(f.tast[narrow].ty, int);
448 let wide = f.conv().promote_bits(full, 32);
450 assert_eq!(f.tast[wide].ty, unsigned);
451 }
452
453 #[test]
454 fn a_bit_field_operand_promotes_by_its_width_without_being_asked() {
455 let mut f = Fixture::new();
459 let unsigned = f.types.int(IntKind::UInt);
460 let int = f.types.int(IntKind::Int);
461 let one = f.zero(int);
462 let again = f.zero(int);
463
464 let narrow = f.bit_field(unsigned, 1);
465 let (lhs, rhs) = f.conv().usual_arithmetic(narrow, one).expect("both are arithmetic");
466 assert_eq!(f.tast[lhs].ty, int);
467 assert_eq!(f.tast[rhs].ty, int);
468
469 let full = f.bit_field(unsigned, 32);
472 let (lhs, rhs) = f.conv().usual_arithmetic(full, again).expect("both are arithmetic");
473 assert_eq!(f.tast[lhs].ty, unsigned);
474 assert_eq!(f.tast[rhs].ty, unsigned);
475 }
476
477 #[test]
478 fn a_bit_field_that_has_already_been_read_still_promotes_by_its_width() {
479 let mut f = Fixture::new();
482 let unsigned = f.types.int(IntKind::UInt);
483 let int = f.types.int(IntKind::Int);
484 let narrow = f.bit_field(unsigned, 1);
485 let read = f.conv().value(narrow);
486
487 let promoted = f.conv().promote(read);
488 assert_eq!(f.tast[promoted].ty, int);
489 }
490
491 #[test]
492 fn the_usual_arithmetic_conversions_move_both_sides_to_one_type() {
493 let mut f = Fixture::new();
494 let int = f.types.int(IntKind::Int);
495 let long = f.types.int(IntKind::Long);
496 let narrow = f.object(int);
497 let wide = f.object(long);
498
499 let (lhs, rhs) = f.conv().usual_arithmetic(narrow, wide).expect("both are arithmetic");
500 assert_eq!(f.tast[lhs].ty, long);
501 assert_eq!(f.tast[rhs].ty, long);
502 }
503
504 #[test]
505 fn a_pointer_pair_has_no_usual_arithmetic_conversion() {
506 let mut f = Fixture::new();
507 let int = f.types.int(IntKind::Int);
508 let pointer = f.types.pointer(int);
509 let left = f.object(pointer);
510 let right = f.object(int);
511
512 assert!(f.conv().usual_arithmetic(left, right).is_none());
513 }
514
515 #[test]
516 fn a_condition_is_a_comparison_against_zero_and_not_a_truncation() {
517 let mut f = Fixture::new();
518 let int = f.types.int(IntKind::Int);
519 let object = f.object(int);
520 let condition = f.conv().to_bool(object);
521
522 assert_eq!(
524 f.text(condition),
525 "convert bool : _Bool\n convert lvalue : int\n decl #0 : int lvalue\n"
526 );
527 }
528
529 #[test]
530 fn a_zero_of_any_integer_type_is_a_null_pointer_constant() {
531 let mut f = Fixture::new();
532 let long = f.types.int(IntKind::Long);
533 let int = f.types.int(IntKind::Int);
534 let pointer = f.types.pointer(int);
535 let zero = f.zero(long);
536 let null = f.conv().to_type(zero, pointer);
537
538 assert_eq!(f.text(null), "convert null-pointer : int *\n const 0 : long\n");
539 }
540
541 #[test]
542 fn a_pointer_that_is_not_a_constant_zero_is_an_ordinary_pointer_conversion() {
543 let mut f = Fixture::new();
544 let int = f.types.int(IntKind::Int);
545 let void = f.types.void();
546 let from = f.types.pointer(void);
547 let to = f.types.pointer(int);
548 let object = f.object(from);
549 let converted = f.conv().to_type(object, to);
550
551 assert_eq!(
552 f.text(converted),
553 "convert pointer : int *\n convert lvalue : void *\n decl #0 : void * lvalue\n"
554 );
555 }
556
557 #[test]
558 fn converting_to_the_type_it_already_has_writes_nothing() {
559 let mut f = Fixture::new();
560 let int = f.types.int(IntKind::Int);
561 let object = f.object(int);
562 let read = f.conv().value(object);
563 let again = f.conv().to_type(read, int);
564
565 assert_eq!(read, again);
566 }
567
568 #[test]
569 fn a_value_is_discarded_by_a_node_rather_than_by_being_ignored() {
570 let mut f = Fixture::new();
571 let int = f.types.int(IntKind::Int);
572 let object = f.object(int);
573 let dropped = f.conv().to_void(object);
574
575 assert_eq!(f.text(dropped), "convert void : void\n decl #0 : int lvalue\n");
576 }
577}