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 {
219 Conversion::Pointer
223 };
224 self.write(kind, expr, target)
225 }
226
227 #[must_use]
233 pub fn is_null_pointer_constant(&self, expr: ExprId) -> bool {
234 match self.tast[expr].kind {
235 ExprKind::Const(value) => self.tast[value] == Const::Int(0),
236 ExprKind::Cast(inner) | ExprKind::Convert { operand: inner, .. } => {
237 self.is_null_pointer_constant(inner)
238 }
239 _ => false,
240 }
241 }
242
243 fn arithmetic(&mut self, expr: ExprId, ty: TypeId) -> ExprId {
245 if self.tast[expr].ty == ty {
246 return expr;
247 }
248 self.write(Conversion::Arithmetic, expr, ty)
249 }
250
251 pub(crate) fn read_as(&mut self, ty: TypeId) -> TypeId {
256 let stripped = match self.types.kind(self.types.canonical(ty)) {
257 TypeKind::Atomic(inner) => inner,
258 _ => ty,
259 };
260 self.types.unqualified(stripped)
261 }
262
263 fn write(&mut self, kind: Conversion, operand: ExprId, ty: TypeId) -> ExprId {
265 let span = self.tast.expr_span(operand);
266 let node = Expr::new(ExprKind::Convert { kind, operand }, ty, Category::Rvalue);
267 self.tast.expr(node, span)
268 }
269}
270
271#[cfg(test)]
272mod tests {
273 use rucc_base::Interner;
274 use rucc_diag::Span;
275 use rucc_target::{TargetInfo, Triple};
276 use rucc_types::{ArrayLen, FunctionType, IntKind, Qualifiers};
277
278 use super::*;
279 use crate::decl::{Decl, DeclKind, DeclList, Definition, Linkage, StorageDuration};
280 use crate::print::Printer;
281
282 struct Fixture {
283 tast: Tast,
284 types: Types,
285 names: Interner,
286 target: TargetInfo,
287 }
288
289 impl Fixture {
290 fn new() -> Fixture {
291 let target =
292 TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().expect("a triple"));
293 Fixture { tast: Tast::new(), types: Types::new(), names: Interner::new(), target }
294 }
295
296 fn conv(&mut self) -> Conv<'_> {
297 Conv { tast: &mut self.tast, types: &mut self.types, target: &self.target }
298 }
299
300 fn object(&mut self, ty: TypeId) -> ExprId {
302 let decl = self.tast.decl(
303 Decl {
304 name: None,
305 ty,
306 kind: DeclKind::Object,
307 linkage: Linkage::None,
308 duration: StorageDuration::Automatic,
309 state: Definition::Defined,
310 alignment: None,
311 constant: false,
312 retained: false,
313 init: None,
314 params: DeclList::EMPTY,
315 body: None,
316 },
317 Span::DUMMY,
318 );
319 self.tast.expr(Expr::new(ExprKind::Decl(decl), ty, Category::Lvalue), Span::DUMMY)
320 }
321
322 fn bit_field(&mut self, ty: TypeId, bits: u32) -> ExprId {
324 let fields = [rucc_types::FieldDecl::bit_field(None, ty, bits)];
325 let id = self.types.declare_record(rucc_types::RecordKind::Struct, None);
326 let laid_out = rucc_types::layout_record(
327 &self.types,
328 rucc_types::RecordKind::Struct,
329 &fields,
330 &rucc_types::RecordOptions::default(),
331 &self.target,
332 )
333 .expect("a layout");
334 self.types.complete_record(id, laid_out);
335 let record = self.types.record(id);
336 let base = self.object(record);
337 self.tast.expr(
338 Expr::new(ExprKind::Member { base, field: 0 }, ty, Category::Bitfield),
339 Span::DUMMY,
340 )
341 }
342
343 fn zero(&mut self, ty: TypeId) -> ExprId {
344 let value = self.tast.add_const(Const::Int(0));
345 self.tast.expr(Expr::new(ExprKind::Const(value), ty, Category::Rvalue), Span::DUMMY)
346 }
347
348 fn text(&self, expr: ExprId) -> String {
349 let mut printer = Printer::new(&self.tast, &self.types, &self.names);
350 printer.expr(expr);
351 printer.finish()
352 }
353 }
354
355 #[test]
356 fn reading_an_object_drops_the_qualifiers_because_they_are_not_part_of_a_value() {
357 let mut f = Fixture::new();
358 let int = f.types.int(IntKind::Int);
359 let constant = f.types.qualified(int, Qualifiers::CONST);
360 let object = f.object(constant);
361 let read = f.conv().value(object);
362
363 assert_eq!(f.tast[read].ty, int);
364 assert_eq!(f.tast[read].category, Category::Rvalue);
365 assert_eq!(f.text(read), "convert lvalue : int\n decl #0 : const int lvalue\n");
366 }
367
368 #[test]
369 fn an_atomic_object_reads_as_the_type_it_wraps() {
370 let mut f = Fixture::new();
371 let int = f.types.int(IntKind::Int);
372 let atomic = f.types.atomic(int);
373 let object = f.object(atomic);
374 let read = f.conv().value(object);
375
376 assert_eq!(f.tast[read].ty, int);
377 }
378
379 #[test]
380 fn an_array_decays_and_is_not_read() {
381 let mut f = Fixture::new();
382 let int = f.types.int(IntKind::Int);
383 let array = f.types.array(int, ArrayLen::Fixed(3));
384 let object = f.object(array);
385 let decayed = f.conv().value(object);
386
387 assert_eq!(f.text(decayed), "convert array-decay : int *\n decl #0 : int[3] lvalue\n");
390 }
391
392 #[test]
393 fn a_function_decays_to_a_pointer_to_itself() {
394 let mut f = Fixture::new();
395 let void = f.types.void();
396 let signature =
397 FunctionType { ret: void, params: Vec::new(), variadic: false, prototyped: true };
398 let function = f.types.function(signature);
399 let designator =
400 f.tast.expr(Expr::new(ExprKind::Error, function, Category::Function), Span::DUMMY);
401 let decayed = f.conv().value(designator);
402
403 assert_eq!(
404 f.text(decayed),
405 "convert function-decay : void (*)(void)\n error : void(void) function\n"
406 );
407 }
408
409 #[test]
410 fn a_narrow_integer_promotes_and_an_int_does_not_move() {
411 let mut f = Fixture::new();
412 let char_type = f.types.int(IntKind::Char);
413 let int = f.types.int(IntKind::Int);
414 let narrow = f.object(char_type);
415 let wide = f.object(int);
416
417 let promoted = f.conv().promote(narrow);
418 assert_eq!(f.tast[promoted].ty, int);
419 assert_eq!(
420 f.text(promoted),
421 "convert arithmetic : int\n convert lvalue : char\n decl #0 : char lvalue\n"
422 );
423
424 let already = f.conv().promote(wide);
426 assert_eq!(f.text(already), "convert lvalue : int\n decl #1 : int lvalue\n");
427 }
428
429 #[test]
430 fn a_bit_field_promotes_by_its_width_and_not_by_its_type() {
431 let mut f = Fixture::new();
432 let unsigned = f.types.int(IntKind::UInt);
433 let int = f.types.int(IntKind::Int);
434 let three = f.object(unsigned);
435 let full = f.object(unsigned);
436
437 let narrow = f.conv().promote_bits(three, 3);
439 assert_eq!(f.tast[narrow].ty, int);
440 let wide = f.conv().promote_bits(full, 32);
442 assert_eq!(f.tast[wide].ty, unsigned);
443 }
444
445 #[test]
446 fn a_bit_field_operand_promotes_by_its_width_without_being_asked() {
447 let mut f = Fixture::new();
451 let unsigned = f.types.int(IntKind::UInt);
452 let int = f.types.int(IntKind::Int);
453 let one = f.zero(int);
454 let again = f.zero(int);
455
456 let narrow = f.bit_field(unsigned, 1);
457 let (lhs, rhs) = f.conv().usual_arithmetic(narrow, one).expect("both are arithmetic");
458 assert_eq!(f.tast[lhs].ty, int);
459 assert_eq!(f.tast[rhs].ty, int);
460
461 let full = f.bit_field(unsigned, 32);
464 let (lhs, rhs) = f.conv().usual_arithmetic(full, again).expect("both are arithmetic");
465 assert_eq!(f.tast[lhs].ty, unsigned);
466 assert_eq!(f.tast[rhs].ty, unsigned);
467 }
468
469 #[test]
470 fn a_bit_field_that_has_already_been_read_still_promotes_by_its_width() {
471 let mut f = Fixture::new();
474 let unsigned = f.types.int(IntKind::UInt);
475 let int = f.types.int(IntKind::Int);
476 let narrow = f.bit_field(unsigned, 1);
477 let read = f.conv().value(narrow);
478
479 let promoted = f.conv().promote(read);
480 assert_eq!(f.tast[promoted].ty, int);
481 }
482
483 #[test]
484 fn the_usual_arithmetic_conversions_move_both_sides_to_one_type() {
485 let mut f = Fixture::new();
486 let int = f.types.int(IntKind::Int);
487 let long = f.types.int(IntKind::Long);
488 let narrow = f.object(int);
489 let wide = f.object(long);
490
491 let (lhs, rhs) = f.conv().usual_arithmetic(narrow, wide).expect("both are arithmetic");
492 assert_eq!(f.tast[lhs].ty, long);
493 assert_eq!(f.tast[rhs].ty, long);
494 }
495
496 #[test]
497 fn a_pointer_pair_has_no_usual_arithmetic_conversion() {
498 let mut f = Fixture::new();
499 let int = f.types.int(IntKind::Int);
500 let pointer = f.types.pointer(int);
501 let left = f.object(pointer);
502 let right = f.object(int);
503
504 assert!(f.conv().usual_arithmetic(left, right).is_none());
505 }
506
507 #[test]
508 fn a_condition_is_a_comparison_against_zero_and_not_a_truncation() {
509 let mut f = Fixture::new();
510 let int = f.types.int(IntKind::Int);
511 let object = f.object(int);
512 let condition = f.conv().to_bool(object);
513
514 assert_eq!(
516 f.text(condition),
517 "convert bool : _Bool\n convert lvalue : int\n decl #0 : int lvalue\n"
518 );
519 }
520
521 #[test]
522 fn a_zero_of_any_integer_type_is_a_null_pointer_constant() {
523 let mut f = Fixture::new();
524 let long = f.types.int(IntKind::Long);
525 let int = f.types.int(IntKind::Int);
526 let pointer = f.types.pointer(int);
527 let zero = f.zero(long);
528 let null = f.conv().to_type(zero, pointer);
529
530 assert_eq!(f.text(null), "convert null-pointer : int *\n const 0 : long\n");
531 }
532
533 #[test]
534 fn a_pointer_that_is_not_a_constant_zero_is_an_ordinary_pointer_conversion() {
535 let mut f = Fixture::new();
536 let int = f.types.int(IntKind::Int);
537 let void = f.types.void();
538 let from = f.types.pointer(void);
539 let to = f.types.pointer(int);
540 let object = f.object(from);
541 let converted = f.conv().to_type(object, to);
542
543 assert_eq!(
544 f.text(converted),
545 "convert pointer : int *\n convert lvalue : void *\n decl #0 : void * lvalue\n"
546 );
547 }
548
549 #[test]
550 fn converting_to_the_type_it_already_has_writes_nothing() {
551 let mut f = Fixture::new();
552 let int = f.types.int(IntKind::Int);
553 let object = f.object(int);
554 let read = f.conv().value(object);
555 let again = f.conv().to_type(read, int);
556
557 assert_eq!(read, again);
558 }
559
560 #[test]
561 fn a_value_is_discarded_by_a_node_rather_than_by_being_ignored() {
562 let mut f = Fixture::new();
563 let int = f.types.int(IntKind::Int);
564 let object = f.object(int);
565 let dropped = f.conv().to_void(object);
566
567 assert_eq!(f.text(dropped), "convert void : void\n decl #0 : int lvalue\n");
568 }
569}