rucc_lower/unit.rs
1//! The module level of the walk: what a translation unit's declarations become.
2//!
3//! Design: `spec/08-ir.md` section 8.9.
4//!
5//! One typed tree becomes one [`Module`]. A file-scope object becomes a global with an image
6//! built from its initializer, a function becomes a [`Func`] whose body is built by
7//! [`body`](mod@crate::body), and a string literal becomes an unnamed constant global that
8//! whatever mentioned it points at.
9//!
10//! # What an image is
11//!
12//! An initializer arrives here already flattened: one entry per scalar that is stored, each
13//! with the byte offset it goes at, with every designator and every nested brace already
14//! resolved. So building the image is a walk over the entries in offset order, filling the gaps
15//! between them with zeros, and the only thing that has to be worked out per entry is whether
16//! the value is a number, a run of bytes from a string literal, or the address of something the
17//! linker has to place.
18//!
19//! # Names
20//!
21//! An object with linkage is known by the name it was written with, and there is nothing to
22//! invent. A `static` inside a function has no linkage and still needs a name in the object
23//! file, so it gets `name.N`, which is what gcc does and is why two functions may each have a
24//! `static int count;` without colliding. A string literal has no name at all and gets
25//! `.Lstr.N`, whose leading dot keeps it out of the symbol table on every target that has the
26//! convention.
27
28use std::cmp::Ordering;
29use std::collections::{BTreeMap, HashMap, HashSet};
30
31use rucc_base::{Interner, Symbol};
32use rucc_diag::{Diagnostic, Span};
33use rucc_ir::{
34 DataList, Datum, Func, Global, Imm, Linkage as IrLinkage, Module, Reloc, SymbolRef, TlsModel,
35 Type,
36};
37use rucc_sema::{
38 Base, Const, Conversion, DeclId, DeclKind, Definition, Eval, ExprId, ExprKind, InitEntry,
39 InitList, Linkage, StorageDuration, StrId, Tast,
40};
41use rucc_target::TargetInfo;
42use rucc_types::{TypeId, TypeKind, Types, compatible};
43
44use crate::abi::{self, Plan};
45use crate::body;
46use crate::reach;
47use crate::repr;
48
49/// Everything the walk reads, which is a checked translation unit and the target it is for.
50///
51/// The interner is mutable because the walk invents names the program never wrote: the label a
52/// string literal is emitted under, and the mangled name of a function-scope `static`.
53#[derive(Debug)]
54pub struct Context<'a> {
55 /// The typed tree.
56 pub tast: &'a Tast,
57 /// The types it points into.
58 pub types: &'a Types,
59 /// What is being compiled for, which is where every width and every alignment comes from.
60 pub target: &'a TargetInfo,
61 /// The name table.
62 pub names: &'a mut Interner,
63}
64
65/// What the walk produced.
66#[derive(Debug)]
67pub struct Lowered {
68 /// The module, which is complete even when something was reported: a construct that is not
69 /// supported yet leaves the rest of the function around it intact.
70 pub module: Module,
71 /// What was reported, in the order it was found.
72 pub diagnostics: Vec<Diagnostic>,
73}
74
75/// Walks a checked translation unit and builds the IR for it.
76///
77/// `name` is the module's name, which is the file the tree came from.
78#[must_use]
79pub fn lower(name: &str, cx: Context<'_>) -> Lowered {
80 let Context { tast, types, target, names } = cx;
81 let module = Module::new(names.intern(name), target);
82 let mut unit = Unit {
83 tast,
84 types,
85 target,
86 names,
87 module,
88 diagnostics: Vec::new(),
89 strings: HashMap::new(),
90 statics: HashMap::new(),
91 done: HashSet::new(),
92 reachable: reach::reachable(tast),
93 };
94 unit.run();
95 Lowered { module: unit.module, diagnostics: unit.diagnostics }
96}
97
98/// The walk over one translation unit, and everything it has built so far.
99pub(crate) struct Unit<'a> {
100 pub(crate) tast: &'a Tast,
101 pub(crate) types: &'a Types,
102 pub(crate) target: &'a TargetInfo,
103 pub(crate) names: &'a mut Interner,
104 pub(crate) module: Module,
105 pub(crate) diagnostics: Vec<Diagnostic>,
106 /// The global each string literal was emitted as, so that two mentions of one literal are
107 /// one object.
108 strings: HashMap<StrId, Symbol>,
109 /// The name each object with no linkage was given.
110 statics: HashMap<DeclId, Symbol>,
111 /// What has been emitted, because a redeclaration is the same declaration seen twice.
112 done: HashSet<DeclId>,
113 /// What something in the file reaches, which is what decides whether a function with
114 /// internal linkage is emitted at all.
115 reachable: HashSet<DeclId>,
116}
117
118// The debug is by hand and short: a translation unit is not something anybody wants printed as
119// a `{:?}`, and the module has a printer of its own for when they do.
120impl std::fmt::Debug for Unit<'_> {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 f.debug_struct("Unit")
123 .field("module", &self.module.counts())
124 .field("diagnostics", &self.diagnostics.len())
125 .finish()
126 }
127}
128
129impl Unit<'_> {
130 /// Every declaration the file made, in the order it made them.
131 fn run(&mut self) {
132 for index in 0..self.tast.top_level().len() {
133 let decl = self.tast.top_level()[index];
134 if !self.done.insert(decl) {
135 continue;
136 }
137 match self.tast[decl].kind {
138 DeclKind::Function => self.function(decl),
139 DeclKind::Object => self.object(decl),
140 }
141 }
142 }
143
144 /// One object with static storage duration.
145 fn object(&mut self, decl: DeclId) {
146 let tast = self.tast;
147 let node = &tast[decl];
148 let (ty, state, init) = (node.ty, node.state, node.init);
149 let (linkage, duration, alignment) = (node.linkage, node.duration, node.alignment);
150 let span = tast.decl_span(decl);
151 if duration == StorageDuration::Automatic {
152 // A block-scope object with automatic storage is a slot or a value in the function
153 // that declares it, and the body is what makes it. Nothing is emitted here.
154 return;
155 }
156
157 let symbol = self.symbol_of(decl);
158 let size = repr::size_of(self.types, self.target, ty);
159 let align = alignment.unwrap_or_else(|| repr::align_of(self.types, self.target, ty));
160 let mut global = Global::new(symbol, size, align);
161 global.linkage = match linkage {
162 Linkage::External => IrLinkage::External,
163 Linkage::Internal | Linkage::None => IrLinkage::Internal,
164 };
165 global.tls = (duration == StorageDuration::Thread).then_some(TlsModel::GlobalDynamic);
166 global.constant = repr::is_read_only(self.types, ty);
167 global.init = match state {
168 // `extern int x;` and nothing else names an object another translation unit
169 // defines. The global is here so that a reference to it has something to resolve
170 // against, and it has no image, which is what makes it a declaration.
171 Definition::Declared => None,
172 Definition::Tentative => Some(self.zeros(size)),
173 Definition::Defined => {
174 let (data, covered) = self.image(init, size, span);
175 // The object is as large as its image when the image is the larger of the two.
176 // A structure whose last member is a flexible array is the only way that
177 // happens: `sizeof` answers without the array and an initializer that fills it
178 // makes an object big enough to hold what was written. C 6.7.2.1p18 leaves the
179 // size to the implementation, gcc grows the object, and this does the same
180 // rather than hand the linker a size the image does not fit in.
181 global.size = size.max(covered);
182 Some(data)
183 }
184 };
185 self.place_global(global);
186 }
187
188 /// One function, with its body when it has one.
189 fn function(&mut self, decl: DeclId) {
190 if self.is_dropped(decl) {
191 return;
192 }
193 let tast = self.tast;
194 let node = &tast[decl];
195 let (ty, linkage, body, align) = (node.ty, node.linkage, node.body, node.alignment);
196 let span = tast.decl_span(decl);
197 if node.name.is_none() {
198 return;
199 }
200 // Which asks the one question the reference to it asks, so that a declaration that
201 // renamed the symbol renames the definition as well and the two still meet.
202 let name = self.symbol_of(decl);
203 let Some(plan) = self.plan(ty, &[], span) else { return };
204
205 let mut func = Func::new(name, plan.signature.clone());
206 func.align = align;
207 func.linkage = match linkage {
208 Linkage::Internal | Linkage::None => IrLinkage::Internal,
209 Linkage::External => IrLinkage::External,
210 };
211 // An inline definition is not an external definition, so what goes in the module is the
212 // declaration and not the body. C 6.7.4p7 says the calls in this unit go to the definition
213 // some other unit holds, which is what the declaration gives them, and glibc's headers
214 // rely on it: every one of their inline definitions would otherwise be a second definition
215 // of a name the library already defines.
216 if body.is_some() && node.inline.emits() {
217 body::lower(self, decl, &mut func, &plan);
218 }
219 self.place_func(func);
220 }
221
222 /// Puts a function in the module under a name something may already be under.
223 ///
224 /// Two declarations of one identifier were merged before this, so the only way one name
225 /// arrives twice is an assembler name that renames one identifier onto another: a
226 /// declaration of `f` renamed to `g` beside a definition of `g` is one symbol written two
227 /// ways, which is what the program asked for and what the linker is going to see. The
228 /// definition wins wherever there is one, since what the declaration is here for is to give
229 /// the calls something to resolve against and the definition does that as well.
230 ///
231 /// A name already carrying a definition keeps it. That is the program defining one symbol
232 /// twice, and the assembler says so with the name in front of it, which is a better message
233 /// than anything available here.
234 fn place_func(&mut self, func: Func) {
235 match self.module.lookup(func.name) {
236 None => {
237 self.module.add_func(func);
238 }
239 Some(SymbolRef::Func(id))
240 if self.module[id].is_declaration() && !func.is_declaration() =>
241 {
242 self.module[id] = func;
243 }
244 Some(_) => {}
245 }
246 }
247
248 /// The same for an object, where a global with no image is the declaration.
249 fn place_global(&mut self, global: Global) {
250 match self.module.lookup(global.name) {
251 None => {
252 self.module.add_global(global);
253 }
254 Some(SymbolRef::Global(id))
255 if self.module[id].init.is_none() && global.init.is_some() =>
256 {
257 self.module[id] = global;
258 }
259 Some(_) => {}
260 }
261 }
262
263 /// Whether this function is one nothing can call, which is the set that is not emitted.
264 ///
265 /// A name with internal linkage is not visible to another translation unit, so a definition
266 /// of one that nothing here refers to is a definition of something that can never run.
267 /// [`reach`](mod@crate::reach) is what worked out which those are, and an attribute that asks
268 /// for the definition to be kept has already been read into the answer.
269 ///
270 /// Nothing is said about it. gcc has `-Wunused-function` for a `static` function nobody
271 /// wrote a call to, which is a warning about the program, and this is not that: the header
272 /// that defines six of them is not the file being compiled and its author is not the person
273 /// reading the output.
274 fn is_dropped(&self, decl: DeclId) -> bool {
275 self.tast[decl].linkage != Linkage::External && !self.reachable.contains(&decl)
276 }
277
278 /// How everything a call to this function type hands over travels, and [`None`] for one the
279 /// walk cannot make.
280 ///
281 /// `actual` is the types of the arguments at a call site, which matter only past the end of
282 /// the prototype: what a variadic argument does is decided from what was written there, and
283 /// there is no parameter to decide it from. A definition passes nothing for it.
284 pub(crate) fn plan(&mut self, ty: TypeId, actual: &[TypeId], span: Span) -> Option<Plan> {
285 self.plan_with(ty, actual, false, span)
286 }
287
288 /// The same, as the call site sees it rather than as the function does.
289 ///
290 /// The two differ for a type that is not a prototype. An old style definition is the one of
291 /// those that knows what its parameters are, and 6.5.2.2p6 checks a call against a prototype
292 /// and against nothing at all otherwise, so a parameter it disagrees with does not make the
293 /// call wrong and cannot be what the argument travels as either: the value at the call is
294 /// the argument's own type and nothing converted it. So a parameter the argument facing it
295 /// is compatible with is used, which is the usual case and is what makes the call go to the
296 /// name, and one it is not compatible with gives way to what was actually written. A call
297 /// like that is undefined behaviour if control reaches it and the file still has to
298 /// translate, which is the same position [`Body::direct`](crate::body) already takes.
299 pub(crate) fn call_plan(&mut self, ty: TypeId, actual: &[TypeId], span: Span) -> Option<Plan> {
300 self.plan_with(ty, actual, true, span)
301 }
302
303 fn plan_with(
304 &mut self,
305 ty: TypeId,
306 actual: &[TypeId],
307 at_call: bool,
308 span: Span,
309 ) -> Option<Plan> {
310 let canonical = self.types.canonical(ty);
311 let canonical = match self.types.kind(canonical) {
312 // A call goes through a pointer to a function, and the type in hand may be either.
313 TypeKind::Pointer(pointee) => self.types.canonical(pointee),
314 _ => canonical,
315 };
316 let TypeKind::Function(id) = self.types.kind(canonical) else {
317 self.unsupported("a call through something that is not a function", span);
318 return None;
319 };
320 let signature = self.types.signature(id);
321 let ret = signature.ret;
322 // A function declared without a prototype takes what it is given, which is what a
323 // signature with no parameters and no end to them says. C23 removed these and this is
324 // what `int f();` means in every dialect before it.
325 let variadic = signature.variadic || !signature.prototyped;
326 let params = if at_call && !signature.prototyped {
327 // An argument past the end of the list has no parameter to travel as, which is what
328 // a call to an unprototyped function with more arguments than the definition takes
329 // is, so the list ends where the arguments do.
330 signature
331 .params
332 .iter()
333 .zip(actual)
334 .map(|(¶m, &arg)| if compatible(self.types, param, arg) { param } else { arg })
335 .collect()
336 } else {
337 signature.params.clone()
338 };
339
340 match abi::plan(self.types, self.target, ret, ¶ms, actual, variadic) {
341 Ok(plan) => Some(plan),
342 Err(what) => {
343 self.unsupported(what, span);
344 None
345 }
346 }
347 }
348
349 /// The image of an initializer: the entries in ascending order, with the gaps zeroed, and
350 /// how many bytes it covers.
351 ///
352 /// The count is the size that was asked for except when a flexible array member was given
353 /// something to hold, which is the one case where an image is larger than the type it is an
354 /// image of.
355 pub(crate) fn image(
356 &mut self,
357 init: Option<InitList>,
358 size: u64,
359 span: Span,
360 ) -> (DataList, u64) {
361 let Some(init) = init else { return (self.zeros(size), size) };
362 let (data, at) = self.pieces(init, size, span);
363 (self.module.push_data(&data), at)
364 }
365
366 /// The data an image is made of, before it becomes a [`DataList`].
367 ///
368 /// This is apart from [`Self::image`] so that an image can be built inside another one,
369 /// which is what a compound literal used as a value in an initializer needs.
370 fn pieces(&mut self, init: InitList, size: u64, span: Span) -> (Vec<Datum>, u64) {
371 let entries = self.in_image_order(&self.tast[init]);
372 let mut packed = self.packed(&entries, size);
373 let mut data: Vec<Datum> = Vec::with_capacity(entries.len());
374 let mut at = 0;
375 for entry in entries {
376 let piece = self.entry(entry, &mut packed, size);
377 if piece.is_empty() {
378 continue;
379 }
380 let covered: u64 = piece.iter().map(|datum| datum.size(&self.module)).sum();
381 match entry.offset.cmp(&at) {
382 Ordering::Greater => data.push(Datum::Zero(entry.offset - at)),
383 // An entry that begins inside the one before it, which is neither the same
384 // place nor a later one. A union whose members are initialized through two
385 // designators is the way to write it. The earlier bytes are already in the
386 // list and the image cannot take them out again, so this is refused, and
387 // nothing here is wrong enough to drop the rest of the image.
388 Ordering::Less => {
389 self.unsupported("an initializer that writes over an earlier one", span);
390 continue;
391 }
392 Ordering::Equal => {}
393 }
394 at = entry.offset + covered;
395 data.extend(piece);
396 }
397 if at < size {
398 // The tail of a partly initialized object, which C says is zero. So is the tail of
399 // an array the initializer did not fill, and so is every byte of padding.
400 data.push(Datum::Zero(size - at));
401 at = size;
402 }
403 (data, at)
404 }
405
406 /// The entries an image is written from, which is not the order they were written in.
407 ///
408 /// A designator names a place, and the places may be named in any order at all:
409 /// `{ .b = 2, .a = 1 }` is the same object as `{ .a = 1, .b = 2 }` and C says so in as many
410 /// words. An image is bytes in ascending order, so the entries are put in that order here.
411 /// The sort is stable, which is what makes the rest of the rule work: naming one place
412 /// twice is legal and the last of them is the one that stands, so among the entries at one
413 /// offset the written order is kept and all but the last are dropped.
414 ///
415 /// A bit-field is never dropped, because several of them share one offset without writing
416 /// over anything. Which bytes they came to is settled by [`Self::packed`] before this runs
417 /// and the whole run goes in under the first entry that has a bit in it.
418 fn in_image_order(&self, entries: &[InitEntry]) -> Vec<InitEntry> {
419 let mut sorted = entries.to_vec();
420 sorted.sort_by_key(|entry| entry.offset);
421 let mut kept: Vec<InitEntry> = Vec::with_capacity(sorted.len());
422 for entry in sorted {
423 if !entry.is_bit_field() {
424 let over = |last: &InitEntry| last.offset == entry.offset && !last.is_bit_field();
425 while kept.last().is_some_and(over) {
426 kept.pop();
427 }
428 }
429 kept.push(entry);
430 }
431 kept
432 }
433
434 /// What one entry of an initializer puts in the image.
435 ///
436 /// A bit-field is not a datum of its own, because two of them can live in one byte and an
437 /// image is written in bytes. They were put together into their bytes by [`Self::packed`]
438 /// before this ran, and the whole run of bytes goes in under the first entry that lies in
439 /// it, which is why a later one in the same run answers with nothing.
440 ///
441 /// The zeroes at the end of a run are left off it, and a run that is nothing but zeroes
442 /// answers with nothing at all. Either way the gap before the next entry covers them, which
443 /// is the same image and is a smaller one to carry, and it is what keeps an object whose
444 /// bit-fields are all zero in `.bss`. A zero at the front of a run or inside one stays, since
445 /// that is where the run starts and what makes it one run. The run comes out of the map
446 /// whatever is in it, so a later entry lying in it answers with nothing for the usual reason
447 /// rather than writing the run a second time.
448 ///
449 /// An entry is usually one datum and a compound literal read is the reason the answer is a
450 /// list: that entry is a whole object and puts as many data in as the object it is.
451 fn entry(&mut self, entry: InitEntry, packed: &mut BTreeMap<u64, u8>, size: u64) -> Vec<Datum> {
452 if entry.is_bit_field() {
453 let Some(bytes) = take_run(packed, entry.offset) else { return Vec::new() };
454 let Some(last) = bytes.iter().rposition(|&byte| byte != 0) else { return Vec::new() };
455 return vec![Datum::Bytes(self.module.push_bytes(&bytes[..=last]))];
456 }
457 if let Some(literal) = self.literal_read(entry.value) {
458 return self.literal_image(literal, self.tast.expr_span(entry.value));
459 }
460 // How much room is left in the object, which is what a string literal longer than the
461 // array it initializes is cut down to. An entry that begins where the object ends is the
462 // initializer of a flexible array member, and there the object grows to hold what was
463 // written rather than the value being cut to fit, so nothing is taken off it.
464 let room = if entry.offset < size { size - entry.offset } else { u64::MAX };
465 self.datum(entry.value, room).into_iter().collect()
466 }
467
468 /// The compound literal an entry reads, if that is what the entry is.
469 ///
470 /// Reading an object is a node of its own, so a literal used as a value comes through as a
471 /// read of a literal. A literal whose address is taken is not a read and is not this: that
472 /// one folds to an address and goes in as a relocation, with the object it points at emitted
473 /// on its own.
474 fn literal_read(&self, value: ExprId) -> Option<DeclId> {
475 let ExprKind::Convert { kind: Conversion::Lvalue, operand } = self.tast[value].kind else {
476 return None;
477 };
478 match self.tast[operand].kind {
479 ExprKind::CompoundLiteral(decl) => Some(decl),
480 _ => None,
481 }
482 }
483
484 /// The bytes a compound literal contributes where it is read, which are its own image.
485 ///
486 /// The literal has static storage duration here, since a file-scope initializer is the only
487 /// place this is reached from, and C 6.7.11p4 is what lets it stand as a constant element.
488 /// Its own initializer is built at the offset the entry is at, so the parent image ends up
489 /// with the literal's bytes laid into it rather than a name pointing at a second object.
490 fn literal_image(&mut self, literal: DeclId, span: Span) -> Vec<Datum> {
491 let size = repr::size_of(self.types, self.target, self.tast[literal].ty);
492 let Some(init) = self.tast[literal].init else {
493 return if size == 0 { Vec::new() } else { vec![Datum::Zero(size)] };
494 };
495 self.pieces(init, size, span).0
496 }
497
498 /// The bit-fields of an initializer, put together into the bytes they lie in.
499 ///
500 /// Every byte a field lies in is in the map, whatever the bits it put there are. It is
501 /// tempting to leave a zero byte out, on the grounds that what an image does not say is zero
502 /// anyway, and it is wrong: the run a field's bytes make is taken out of the map from the
503 /// byte the field starts at, so a field whose first byte happens to be zero would have its
504 /// whole run left behind and `struct { unsigned f : 20; } x = { 0x12300 };` would read as
505 /// zero. A run that is all zeroes is written as zeroes by [`Self::entry`], so an object that
506 /// really is zero still costs nothing in the image.
507 ///
508 /// A field named twice takes only the bits of the field, so the last of them stands and does
509 /// not read as the two values together.
510 fn packed(&mut self, entries: &[InitEntry], size: u64) -> BTreeMap<u64, u8> {
511 let mut bytes = BTreeMap::new();
512 for entry in entries.iter().filter(|entry| entry.is_bit_field()) {
513 let Some(folded) = self.fold(entry.value) else { continue };
514 let Const::Int(number) = folded else {
515 let span = self.tast.expr_span(entry.value);
516 let what = "a bit-field initialized by something that is not an integer";
517 self.unsupported(what, span);
518 continue;
519 };
520 let width = entry.bit_width;
521 let ones = if width >= 128 { u128::MAX } else { (1u128 << width) - 1 };
522 let mut mask = ones << entry.bit_offset;
523 let mut placed = ((number as u128) & ones) << entry.bit_offset;
524 let mut at = entry.offset;
525 while mask != 0 && at < size {
526 let (bits, keep) = ((placed & 0xff) as u8, !((mask & 0xff) as u8));
527 let byte = bytes.entry(at).or_insert(0);
528 *byte = (*byte & keep) | bits;
529 mask >>= 8;
530 placed >>= 8;
531 at += 1;
532 }
533 }
534 bytes
535 }
536
537 /// One entry of an image, given how many bytes are left in the object it goes in.
538 fn datum(&mut self, value: ExprId, room: u64) -> Option<Datum> {
539 let tast = self.tast;
540 let ty = tast[value].ty;
541 let span = tast.expr_span(value);
542 if let TypeKind::Array { .. } = self.types.kind(self.types.canonical(ty)) {
543 // An array in an initializer is a string literal initializing it, because that is
544 // the only way an array is ever a value. `char s[2] = "hi";` drops the terminator,
545 // which is the one case where the literal is longer than what it initializes, and
546 // the front end has already given the value the type of the array it is filling, so
547 // the type is what says how many of the literal's bytes are part of it. `room` is
548 // still consulted because a flexible array member is filled by a literal that keeps
549 // its own type and there is no size in the object for it to be cut to.
550 let ExprKind::Str(id) = tast[value].kind else {
551 self.unsupported("this initializer", span);
552 return None;
553 };
554 let bytes = tast[id].bytes(self.target);
555 let holds = repr::size_of(self.types, self.target, ty);
556 let take = bytes.len().min(cap(holds)).min(cap(room));
557 return Some(Datum::Bytes(self.module.push_bytes(&bytes[..take])));
558 }
559
560 let size = repr::size_of(self.types, self.target, ty);
561 match self.fold(value)? {
562 Const::Int(number) => {
563 let ty = repr::value_type(self.types, self.target, ty)?;
564 // An integer constant of pointer type is a null pointer constant, which is what
565 // `NULL` is, or an address the program wrote as a number. An image is bytes and
566 // `ptr` says nothing about how many, so it goes in as the integer it is at the
567 // width the target's addresses have. An address the linker has to fill in is
568 // the arm below, and is the only one that stays a pointer.
569 let ty = if ty.is_ptr() { Type::int(self.target.pointer_width) } else { ty };
570 let imm = self.module.add_imm(Imm::int(number, ty));
571 Some(Datum::Scalar { ty, value: imm })
572 }
573 Const::Float(number) => {
574 let ty = repr::value_type(self.types, self.target, ty)?;
575 let imm = self.module.add_imm(Imm::from_bits(number.to_bits()));
576 Some(Datum::Scalar { ty, value: imm })
577 }
578 Const::Address(address) => {
579 let symbol = match address.base {
580 Base::Decl(decl) => {
581 // A compound literal is an object nothing declares, so the address of
582 // one is also the only thing that asks for it to be emitted. Without
583 // this the image names a symbol the module never defines and the link
584 // is what finds out. Anything with a name of its own is left alone,
585 // since the walk over the unit reaches those on its own.
586 if self.tast[decl].name.is_none() {
587 self.local_static(decl);
588 }
589 self.symbol_of(decl)
590 }
591 Base::Str(id) => self.string(id),
592 };
593 let addend = i64::try_from(address.offset).unwrap_or(0);
594 let size = u32::try_from(size).unwrap_or(0);
595 Some(Datum::Addr(self.module.add_reloc(Reloc { symbol, addend, size })))
596 }
597 }
598 }
599
600 /// An image of nothing but zeros, which is what a tentative definition has.
601 fn zeros(&mut self, size: u64) -> DataList {
602 if size == 0 {
603 return DataList::EMPTY;
604 }
605 self.module.push_data(&[Datum::Zero(size)])
606 }
607
608 /// The global a string literal is emitted as, making it the first time it is asked for.
609 pub(crate) fn string(&mut self, id: StrId) -> Symbol {
610 if let Some(&symbol) = self.strings.get(&id) {
611 return symbol;
612 }
613 let literal = &self.tast[id];
614 let bytes = literal.bytes(self.target);
615 let align = literal.encoding.element_width(self.target) / 8;
616 let symbol = self.names.intern(&format!(".Lstr.{}", self.strings.len()));
617
618 let mut global = Global::new(symbol, bytes.len() as u64, align.max(1));
619 global.linkage = IrLinkage::Internal;
620 // Not because the type says so, since a literal is an array of `char` and not of
621 // `const char`, but because writing to one is undefined and every target puts them
622 // somewhere read-only.
623 global.constant = true;
624 let range = self.module.push_bytes(&bytes);
625 global.init = Some(self.module.push_data(&[Datum::Bytes(range)]));
626 self.module.add_global(global);
627 self.strings.insert(id, symbol);
628 symbol
629 }
630
631 /// The name the C library gives a function the program named with the `__builtin_` prefix,
632 /// and nothing for every other name.
633 ///
634 /// `__builtin_abort` is a call to `abort`: the prefix is how a program reaches the function
635 /// the library promises where a macro or a definition of its own has taken the plain name,
636 /// so the two spellings are one function and the one the linker will look for is the short
637 /// one. Which names those are is [`rucc_sema::library_name`]'s to say, since it is the same
638 /// answer the front end declared them out of.
639 fn library_name(&mut self, name: Symbol) -> Option<Symbol> {
640 let library = rucc_sema::library_name(self.names.resolve(name))?;
641 Some(self.names.intern(library))
642 }
643
644 /// The name an object or a function is known by in the object file.
645 pub(crate) fn symbol_of(&mut self, decl: DeclId) -> Symbol {
646 let tast = self.tast;
647 let node = &tast[decl];
648 // The assembler name a declaration wrote, which is the symbol whatever the identifier
649 // spells. It stands for a `static` and for a local one as well as for a name the linker
650 // sees, so it is read before anything else here: a program that renames a name has said
651 // what the symbol is, and the numbering below is for the ones that have not.
652 if let Some(label) = node.asm_label {
653 let spelling: String =
654 tast[label].elements.iter().filter_map(|&unit| char::from_u32(unit)).collect();
655 return self.names.intern(&spelling);
656 }
657 if node.linkage != Linkage::None {
658 let Some(name) = node.name else { return self.names.intern(".Lanon") };
659 return self.library_name(name).unwrap_or(name);
660 }
661 if let Some(&symbol) = self.statics.get(&decl) {
662 return symbol;
663 }
664 // A `static` in a function, or a compound literal with static storage duration. The
665 // number is what makes two of them in two functions two objects.
666 let base = match node.name {
667 Some(name) => self.names.resolve(name).to_string(),
668 None => ".Lanon".to_string(),
669 };
670 let symbol = self.names.intern(&format!("{base}.{}", self.statics.len()));
671 self.statics.insert(decl, symbol);
672 symbol
673 }
674
675 /// Emits the global for an object with static storage duration declared inside a function.
676 pub(crate) fn local_static(&mut self, decl: DeclId) {
677 if !self.done.insert(decl) {
678 return;
679 }
680 match self.tast[decl].kind {
681 // A function declared inside a body is a declaration of the function, not an
682 // object with static storage that happens to be one.
683 DeclKind::Function => self.function(decl),
684 DeclKind::Object => self.object(decl),
685 }
686 }
687
688 /// The value of a constant expression, reporting what folding it reported.
689 fn fold(&mut self, expr: ExprId) -> Option<Const> {
690 let mut eval = Eval::new(self.tast, self.types, self.target, self.names);
691 let folded = eval.constant(expr);
692 let reported = eval.finish();
693 self.diagnostics.extend(reported);
694 match folded {
695 Ok(value) => Some(value),
696 Err(stop) => {
697 if !stop.poisoned {
698 let span = self.tast.expr_span(stop.at);
699 self.unsupported("an initializer this compiler cannot fold", span);
700 }
701 None
702 }
703 }
704 }
705
706 /// Reports a construct the walk does not build IR for yet.
707 pub(crate) fn unsupported(&mut self, what: &str, span: Span) {
708 self.diagnostics.push(
709 Diagnostic::error(format!("{what} is not supported yet"), span).with_code("E0519"),
710 );
711 }
712
713 /// Reports a call to a builtin this compiler knows the name of and does nothing with.
714 ///
715 /// It is its own message rather than [`Self::unsupported`] because the construct is not the
716 /// problem: a call is a call, and what is missing is the one function it goes to. The note is
717 /// what a reader needs, since a builtin is the one name a programmer does not expect to have
718 /// to provide and the alternative to this message is a linker asking them for it.
719 pub(crate) fn missing_builtin(&mut self, spelled: &str, span: Span) {
720 let message = format!("`{spelled}` is not implemented yet");
721 let note = "a call to it would go to a symbol no object file defines, so this is refused \
722 here rather than at the link";
723 self.diagnostics.push(Diagnostic::error(message, span).with_code("E0686").note(note, span));
724 }
725}
726
727/// A count of bytes as a length of a slice of them, saturating on a target whose addresses are
728/// wider than this host's.
729fn cap(bytes: u64) -> usize {
730 usize::try_from(bytes).unwrap_or(usize::MAX)
731}
732
733/// The run of bytes a bit-field entry starts, taken out of the map.
734///
735/// [`None`] when there is no byte at that offset, which means an earlier entry in the same run
736/// already took it, since [`Unit::packed`] puts every byte a field lies in into the map.
737fn take_run(bytes: &mut BTreeMap<u64, u8>, start: u64) -> Option<Vec<u8>> {
738 let mut run = vec![bytes.remove(&start)?];
739 let mut at = start + 1;
740 while let Some(byte) = bytes.remove(&at) {
741 run.push(byte);
742 at += 1;
743 }
744 Some(run)
745}