1use 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, TlsModel, Type,
35};
36use rucc_sema::{
37 Base, Const, DeclId, DeclKind, Definition, Eval, ExprId, ExprKind, InitEntry, InitList,
38 Linkage, StorageDuration, StrId, Tast,
39};
40use rucc_target::TargetInfo;
41use rucc_types::{TypeId, TypeKind, Types};
42
43use crate::abi::{self, Plan};
44use crate::body;
45use crate::repr;
46
47#[derive(Debug)]
52pub struct Context<'a> {
53 pub tast: &'a Tast,
55 pub types: &'a Types,
57 pub target: &'a TargetInfo,
59 pub names: &'a mut Interner,
61}
62
63#[derive(Debug)]
65pub struct Lowered {
66 pub module: Module,
69 pub diagnostics: Vec<Diagnostic>,
71}
72
73#[must_use]
77pub fn lower(name: &str, cx: Context<'_>) -> Lowered {
78 let Context { tast, types, target, names } = cx;
79 let module = Module::new(names.intern(name), target);
80 let mut unit = Unit {
81 tast,
82 types,
83 target,
84 names,
85 module,
86 diagnostics: Vec::new(),
87 strings: HashMap::new(),
88 statics: HashMap::new(),
89 done: HashSet::new(),
90 };
91 unit.run();
92 Lowered { module: unit.module, diagnostics: unit.diagnostics }
93}
94
95pub(crate) struct Unit<'a> {
97 pub(crate) tast: &'a Tast,
98 pub(crate) types: &'a Types,
99 pub(crate) target: &'a TargetInfo,
100 pub(crate) names: &'a mut Interner,
101 pub(crate) module: Module,
102 pub(crate) diagnostics: Vec<Diagnostic>,
103 strings: HashMap<StrId, Symbol>,
106 statics: HashMap<DeclId, Symbol>,
108 done: HashSet<DeclId>,
110}
111
112impl std::fmt::Debug for Unit<'_> {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 f.debug_struct("Unit")
117 .field("module", &self.module.counts())
118 .field("diagnostics", &self.diagnostics.len())
119 .finish()
120 }
121}
122
123impl Unit<'_> {
124 fn run(&mut self) {
126 for index in 0..self.tast.top_level().len() {
127 let decl = self.tast.top_level()[index];
128 if !self.done.insert(decl) {
129 continue;
130 }
131 match self.tast[decl].kind {
132 DeclKind::Function => self.function(decl),
133 DeclKind::Object => self.object(decl),
134 }
135 }
136 }
137
138 fn object(&mut self, decl: DeclId) {
140 let tast = self.tast;
141 let node = &tast[decl];
142 let (ty, state, init) = (node.ty, node.state, node.init);
143 let (linkage, duration, alignment) = (node.linkage, node.duration, node.alignment);
144 let span = tast.decl_span(decl);
145 if duration == StorageDuration::Automatic {
146 return;
149 }
150
151 let symbol = self.symbol_of(decl);
152 let size = repr::size_of(self.types, self.target, ty);
153 let align = alignment.unwrap_or_else(|| repr::align_of(self.types, self.target, ty));
154 let mut global = Global::new(symbol, size, align);
155 global.linkage = match linkage {
156 Linkage::External => IrLinkage::External,
157 Linkage::Internal | Linkage::None => IrLinkage::Internal,
158 };
159 global.tls = (duration == StorageDuration::Thread).then_some(TlsModel::GlobalDynamic);
160 global.constant = repr::is_read_only(self.types, ty);
161 global.init = match state {
162 Definition::Declared => None,
166 Definition::Tentative => Some(self.zeros(size)),
167 Definition::Defined => Some(self.image(init, size, span)),
168 };
169 self.module.add_global(global);
170 }
171
172 fn function(&mut self, decl: DeclId) {
174 let tast = self.tast;
175 let node = &tast[decl];
176 let (ty, linkage, body) = (node.ty, node.linkage, node.body);
177 let span = tast.decl_span(decl);
178 let Some(name) = node.name else { return };
179 let Some(plan) = self.plan(ty, &[], span) else { return };
180
181 let mut func = Func::new(name, plan.signature.clone());
182 func.linkage = match linkage {
183 Linkage::Internal | Linkage::None => IrLinkage::Internal,
184 Linkage::External => IrLinkage::External,
185 };
186 if body.is_some() {
187 body::lower(self, decl, &mut func, &plan);
188 }
189 self.module.add_func(func);
190 }
191
192 pub(crate) fn plan(&mut self, ty: TypeId, actual: &[TypeId], span: Span) -> Option<Plan> {
199 let canonical = self.types.canonical(ty);
200 let canonical = match self.types.kind(canonical) {
201 TypeKind::Pointer(pointee) => self.types.canonical(pointee),
203 _ => canonical,
204 };
205 let TypeKind::Function(id) = self.types.kind(canonical) else {
206 self.unsupported("a call through something that is not a function", span);
207 return None;
208 };
209 let signature = self.types.signature(id);
210 let ret = signature.ret;
211 let variadic = signature.variadic || !signature.prototyped;
215 let params = signature.params.clone();
216
217 match abi::plan(self.types, self.target, ret, ¶ms, actual, variadic) {
218 Ok(plan) => Some(plan),
219 Err(what) => {
220 self.unsupported(what, span);
221 None
222 }
223 }
224 }
225
226 pub(crate) fn image(&mut self, init: Option<InitList>, size: u64, span: Span) -> DataList {
228 let Some(init) = init else { return self.zeros(size) };
229 let entries = self.in_image_order(&self.tast[init]);
230 let mut packed = self.packed(&entries, size);
231 let mut data: Vec<Datum> = Vec::with_capacity(entries.len());
232 let mut at = 0;
233 for entry in entries {
234 let Some(datum) = self.entry(entry, &mut packed, size) else { continue };
235 match entry.offset.cmp(&at) {
236 Ordering::Greater => data.push(Datum::Zero(entry.offset - at)),
237 Ordering::Less => {
243 self.unsupported("an initializer that writes over an earlier one", span);
244 continue;
245 }
246 Ordering::Equal => {}
247 }
248 at = entry.offset + datum.size(&self.module);
249 data.push(datum);
250 }
251 if at < size {
252 data.push(Datum::Zero(size - at));
255 }
256 self.module.push_data(&data)
257 }
258
259 fn in_image_order(&self, entries: &[InitEntry]) -> Vec<InitEntry> {
272 let mut sorted = entries.to_vec();
273 sorted.sort_by_key(|entry| entry.offset);
274 let mut kept: Vec<InitEntry> = Vec::with_capacity(sorted.len());
275 for entry in sorted {
276 if !entry.is_bit_field() {
277 let over = |last: &InitEntry| last.offset == entry.offset && !last.is_bit_field();
278 while kept.last().is_some_and(over) {
279 kept.pop();
280 }
281 }
282 kept.push(entry);
283 }
284 kept
285 }
286
287 fn entry(
294 &mut self,
295 entry: InitEntry,
296 packed: &mut BTreeMap<u64, u8>,
297 size: u64,
298 ) -> Option<Datum> {
299 if entry.is_bit_field() {
300 let bytes = take_run(packed, entry.offset)?;
301 return Some(Datum::Bytes(self.module.push_bytes(&bytes)));
302 }
303 let room = size.saturating_sub(entry.offset);
304 self.datum(entry.value, room)
305 }
306
307 fn packed(&mut self, entries: &[InitEntry], size: u64) -> BTreeMap<u64, u8> {
314 let mut bytes = BTreeMap::new();
315 for entry in entries.iter().filter(|entry| entry.is_bit_field()) {
316 let Some(folded) = self.fold(entry.value) else { continue };
317 let Const::Int(number) = folded else {
318 let span = self.tast.expr_span(entry.value);
319 let what = "a bit-field initialized by something that is not an integer";
320 self.unsupported(what, span);
321 continue;
322 };
323 let width = entry.bit_width;
324 let ones = if width >= 128 { u128::MAX } else { (1u128 << width) - 1 };
325 let mut mask = ones << entry.bit_offset;
326 let mut placed = ((number as u128) & ones) << entry.bit_offset;
327 let mut at = entry.offset;
328 while mask != 0 && at < size {
329 let (bits, keep) = ((placed & 0xff) as u8, !((mask & 0xff) as u8));
330 if bits != 0 || bytes.contains_key(&at) {
331 let byte = bytes.entry(at).or_insert(0);
332 *byte = (*byte & keep) | bits;
333 }
334 mask >>= 8;
335 placed >>= 8;
336 at += 1;
337 }
338 }
339 bytes
340 }
341
342 fn datum(&mut self, value: ExprId, room: u64) -> Option<Datum> {
344 let tast = self.tast;
345 let ty = tast[value].ty;
346 let span = tast.expr_span(value);
347 if let TypeKind::Array { .. } = self.types.kind(self.types.canonical(ty)) {
348 let ExprKind::Str(id) = tast[value].kind else {
352 self.unsupported("this initializer", span);
353 return None;
354 };
355 let bytes = tast[id].bytes(self.target);
356 let take = bytes.len().min(usize::try_from(room).unwrap_or(usize::MAX));
357 return Some(Datum::Bytes(self.module.push_bytes(&bytes[..take])));
358 }
359
360 let size = repr::size_of(self.types, self.target, ty);
361 match self.fold(value)? {
362 Const::Int(number) => {
363 let ty = repr::value_type(self.types, self.target, ty)?;
364 let ty = if ty.is_ptr() { Type::int(self.target.pointer_width) } else { ty };
370 let imm = self.module.add_imm(Imm::int(number, ty));
371 Some(Datum::Scalar { ty, value: imm })
372 }
373 Const::Float(number) => {
374 let ty = repr::value_type(self.types, self.target, ty)?;
375 let imm = self.module.add_imm(Imm::from_bits(number.to_bits()));
376 Some(Datum::Scalar { ty, value: imm })
377 }
378 Const::Address(address) => {
379 let symbol = match address.base {
380 Base::Decl(decl) => self.symbol_of(decl),
381 Base::Str(id) => self.string(id),
382 };
383 let addend = i64::try_from(address.offset).unwrap_or(0);
384 let size = u32::try_from(size).unwrap_or(0);
385 Some(Datum::Addr(self.module.add_reloc(Reloc { symbol, addend, size })))
386 }
387 }
388 }
389
390 fn zeros(&mut self, size: u64) -> DataList {
392 if size == 0 {
393 return DataList::EMPTY;
394 }
395 self.module.push_data(&[Datum::Zero(size)])
396 }
397
398 pub(crate) fn string(&mut self, id: StrId) -> Symbol {
400 if let Some(&symbol) = self.strings.get(&id) {
401 return symbol;
402 }
403 let literal = &self.tast[id];
404 let bytes = literal.bytes(self.target);
405 let align = literal.encoding.element_width(self.target) / 8;
406 let symbol = self.names.intern(&format!(".Lstr.{}", self.strings.len()));
407
408 let mut global = Global::new(symbol, bytes.len() as u64, align.max(1));
409 global.linkage = IrLinkage::Internal;
410 global.constant = true;
414 let range = self.module.push_bytes(&bytes);
415 global.init = Some(self.module.push_data(&[Datum::Bytes(range)]));
416 self.module.add_global(global);
417 self.strings.insert(id, symbol);
418 symbol
419 }
420
421 pub(crate) fn symbol_of(&mut self, decl: DeclId) -> Symbol {
423 let tast = self.tast;
424 let node = &tast[decl];
425 if node.linkage != Linkage::None {
426 return node.name.unwrap_or_else(|| self.names.intern(".Lanon"));
427 }
428 if let Some(&symbol) = self.statics.get(&decl) {
429 return symbol;
430 }
431 let base = match node.name {
434 Some(name) => self.names.resolve(name).to_string(),
435 None => ".Lanon".to_string(),
436 };
437 let symbol = self.names.intern(&format!("{base}.{}", self.statics.len()));
438 self.statics.insert(decl, symbol);
439 symbol
440 }
441
442 pub(crate) fn local_static(&mut self, decl: DeclId) {
444 if !self.done.insert(decl) {
445 return;
446 }
447 match self.tast[decl].kind {
448 DeclKind::Function => self.function(decl),
451 DeclKind::Object => self.object(decl),
452 }
453 }
454
455 fn fold(&mut self, expr: ExprId) -> Option<Const> {
457 let mut eval = Eval::new(self.tast, self.types, self.target, self.names);
458 let folded = eval.constant(expr);
459 let reported = eval.finish();
460 self.diagnostics.extend(reported);
461 match folded {
462 Ok(value) => Some(value),
463 Err(stop) => {
464 if !stop.poisoned {
465 let span = self.tast.expr_span(stop.at);
466 self.unsupported("an initializer this compiler cannot fold", span);
467 }
468 None
469 }
470 }
471 }
472
473 pub(crate) fn unsupported(&mut self, what: &str, span: Span) {
475 self.diagnostics.push(
476 Diagnostic::error(format!("{what} is not supported yet"), span).with_code("E0519"),
477 );
478 }
479}
480
481fn take_run(bytes: &mut BTreeMap<u64, u8>, start: u64) -> Option<Vec<u8>> {
486 let mut run = vec![bytes.remove(&start)?];
487 let mut at = start + 1;
488 while let Some(byte) = bytes.remove(&at) {
489 run.push(byte);
490 at += 1;
491 }
492 Some(run)
493}