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 init: None,
312 params: DeclList::EMPTY,
313 body: None,
314 },
315 Span::DUMMY,
316 );
317 self.tast.expr(Expr::new(ExprKind::Decl(decl), ty, Category::Lvalue), Span::DUMMY)
318 }
319
320 fn bit_field(&mut self, ty: TypeId, bits: u32) -> ExprId {
322 let fields = [rucc_types::FieldDecl::bit_field(None, ty, bits)];
323 let id = self.types.declare_record(rucc_types::RecordKind::Struct, None);
324 let laid_out = rucc_types::layout_record(
325 &self.types,
326 rucc_types::RecordKind::Struct,
327 &fields,
328 &rucc_types::RecordOptions::default(),
329 &self.target,
330 )
331 .expect("a layout");
332 self.types.complete_record(id, laid_out);
333 let record = self.types.record(id);
334 let base = self.object(record);
335 self.tast.expr(
336 Expr::new(ExprKind::Member { base, field: 0 }, ty, Category::Bitfield),
337 Span::DUMMY,
338 )
339 }
340
341 fn zero(&mut self, ty: TypeId) -> ExprId {
342 let value = self.tast.add_const(Const::Int(0));
343 self.tast.expr(Expr::new(ExprKind::Const(value), ty, Category::Rvalue), Span::DUMMY)
344 }
345
346 fn text(&self, expr: ExprId) -> String {
347 let mut printer = Printer::new(&self.tast, &self.types, &self.names);
348 printer.expr(expr);
349 printer.finish()
350 }
351 }
352
353 #[test]
354 fn reading_an_object_drops_the_qualifiers_because_they_are_not_part_of_a_value() {
355 let mut f = Fixture::new();
356 let int = f.types.int(IntKind::Int);
357 let constant = f.types.qualified(int, Qualifiers::CONST);
358 let object = f.object(constant);
359 let read = f.conv().value(object);
360
361 assert_eq!(f.tast[read].ty, int);
362 assert_eq!(f.tast[read].category, Category::Rvalue);
363 assert_eq!(f.text(read), "convert lvalue : int\n decl #0 : const int lvalue\n");
364 }
365
366 #[test]
367 fn an_atomic_object_reads_as_the_type_it_wraps() {
368 let mut f = Fixture::new();
369 let int = f.types.int(IntKind::Int);
370 let atomic = f.types.atomic(int);
371 let object = f.object(atomic);
372 let read = f.conv().value(object);
373
374 assert_eq!(f.tast[read].ty, int);
375 }
376
377 #[test]
378 fn an_array_decays_and_is_not_read() {
379 let mut f = Fixture::new();
380 let int = f.types.int(IntKind::Int);
381 let array = f.types.array(int, ArrayLen::Fixed(3));
382 let object = f.object(array);
383 let decayed = f.conv().value(object);
384
385 assert_eq!(f.text(decayed), "convert array-decay : int *\n decl #0 : int [3] lvalue\n");
388 }
389
390 #[test]
391 fn a_function_decays_to_a_pointer_to_itself() {
392 let mut f = Fixture::new();
393 let void = f.types.void();
394 let signature =
395 FunctionType { ret: void, params: Vec::new(), variadic: false, prototyped: true };
396 let function = f.types.function(signature);
397 let designator =
398 f.tast.expr(Expr::new(ExprKind::Error, function, Category::Function), Span::DUMMY);
399 let decayed = f.conv().value(designator);
400
401 assert_eq!(
402 f.text(decayed),
403 "convert function-decay : void (*)(void)\n error : void (void) function\n"
404 );
405 }
406
407 #[test]
408 fn a_narrow_integer_promotes_and_an_int_does_not_move() {
409 let mut f = Fixture::new();
410 let char_type = f.types.int(IntKind::Char);
411 let int = f.types.int(IntKind::Int);
412 let narrow = f.object(char_type);
413 let wide = f.object(int);
414
415 let promoted = f.conv().promote(narrow);
416 assert_eq!(f.tast[promoted].ty, int);
417 assert_eq!(
418 f.text(promoted),
419 "convert arithmetic : int\n convert lvalue : char\n decl #0 : char lvalue\n"
420 );
421
422 let already = f.conv().promote(wide);
424 assert_eq!(f.text(already), "convert lvalue : int\n decl #1 : int lvalue\n");
425 }
426
427 #[test]
428 fn a_bit_field_promotes_by_its_width_and_not_by_its_type() {
429 let mut f = Fixture::new();
430 let unsigned = f.types.int(IntKind::UInt);
431 let int = f.types.int(IntKind::Int);
432 let three = f.object(unsigned);
433 let full = f.object(unsigned);
434
435 let narrow = f.conv().promote_bits(three, 3);
437 assert_eq!(f.tast[narrow].ty, int);
438 let wide = f.conv().promote_bits(full, 32);
440 assert_eq!(f.tast[wide].ty, unsigned);
441 }
442
443 #[test]
444 fn a_bit_field_operand_promotes_by_its_width_without_being_asked() {
445 let mut f = Fixture::new();
449 let unsigned = f.types.int(IntKind::UInt);
450 let int = f.types.int(IntKind::Int);
451 let one = f.zero(int);
452 let again = f.zero(int);
453
454 let narrow = f.bit_field(unsigned, 1);
455 let (lhs, rhs) = f.conv().usual_arithmetic(narrow, one).expect("both are arithmetic");
456 assert_eq!(f.tast[lhs].ty, int);
457 assert_eq!(f.tast[rhs].ty, int);
458
459 let full = f.bit_field(unsigned, 32);
462 let (lhs, rhs) = f.conv().usual_arithmetic(full, again).expect("both are arithmetic");
463 assert_eq!(f.tast[lhs].ty, unsigned);
464 assert_eq!(f.tast[rhs].ty, unsigned);
465 }
466
467 #[test]
468 fn a_bit_field_that_has_already_been_read_still_promotes_by_its_width() {
469 let mut f = Fixture::new();
472 let unsigned = f.types.int(IntKind::UInt);
473 let int = f.types.int(IntKind::Int);
474 let narrow = f.bit_field(unsigned, 1);
475 let read = f.conv().value(narrow);
476
477 let promoted = f.conv().promote(read);
478 assert_eq!(f.tast[promoted].ty, int);
479 }
480
481 #[test]
482 fn the_usual_arithmetic_conversions_move_both_sides_to_one_type() {
483 let mut f = Fixture::new();
484 let int = f.types.int(IntKind::Int);
485 let long = f.types.int(IntKind::Long);
486 let narrow = f.object(int);
487 let wide = f.object(long);
488
489 let (lhs, rhs) = f.conv().usual_arithmetic(narrow, wide).expect("both are arithmetic");
490 assert_eq!(f.tast[lhs].ty, long);
491 assert_eq!(f.tast[rhs].ty, long);
492 }
493
494 #[test]
495 fn a_pointer_pair_has_no_usual_arithmetic_conversion() {
496 let mut f = Fixture::new();
497 let int = f.types.int(IntKind::Int);
498 let pointer = f.types.pointer(int);
499 let left = f.object(pointer);
500 let right = f.object(int);
501
502 assert!(f.conv().usual_arithmetic(left, right).is_none());
503 }
504
505 #[test]
506 fn a_condition_is_a_comparison_against_zero_and_not_a_truncation() {
507 let mut f = Fixture::new();
508 let int = f.types.int(IntKind::Int);
509 let object = f.object(int);
510 let condition = f.conv().to_bool(object);
511
512 assert_eq!(
514 f.text(condition),
515 "convert bool : _Bool\n convert lvalue : int\n decl #0 : int lvalue\n"
516 );
517 }
518
519 #[test]
520 fn a_zero_of_any_integer_type_is_a_null_pointer_constant() {
521 let mut f = Fixture::new();
522 let long = f.types.int(IntKind::Long);
523 let int = f.types.int(IntKind::Int);
524 let pointer = f.types.pointer(int);
525 let zero = f.zero(long);
526 let null = f.conv().to_type(zero, pointer);
527
528 assert_eq!(f.text(null), "convert null-pointer : int *\n const 0 : long\n");
529 }
530
531 #[test]
532 fn a_pointer_that_is_not_a_constant_zero_is_an_ordinary_pointer_conversion() {
533 let mut f = Fixture::new();
534 let int = f.types.int(IntKind::Int);
535 let void = f.types.void();
536 let from = f.types.pointer(void);
537 let to = f.types.pointer(int);
538 let object = f.object(from);
539 let converted = f.conv().to_type(object, to);
540
541 assert_eq!(
542 f.text(converted),
543 "convert pointer : int *\n convert lvalue : void *\n decl #0 : void * lvalue\n"
544 );
545 }
546
547 #[test]
548 fn converting_to_the_type_it_already_has_writes_nothing() {
549 let mut f = Fixture::new();
550 let int = f.types.int(IntKind::Int);
551 let object = f.object(int);
552 let read = f.conv().value(object);
553 let again = f.conv().to_type(read, int);
554
555 assert_eq!(read, again);
556 }
557
558 #[test]
559 fn a_value_is_discarded_by_a_node_rather_than_by_being_ignored() {
560 let mut f = Fixture::new();
561 let int = f.types.int(IntKind::Int);
562 let object = f.object(int);
563 let dropped = f.conv().to_void(object);
564
565 assert_eq!(f.text(dropped), "convert void : void\n decl #0 : int lvalue\n");
566 }
567}