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