1use std::cmp::Ordering;
29use std::collections::{BTreeMap, HashMap, HashSet};
30
31use rucc_base::{Interner, Symbol};
32use rucc_diag::{Diagnostic, Span};
33use rucc_ir::{DataList, Datum, Func, Global, Imm, Linkage as IrLinkage, Module, Reloc, TlsModel};
34use rucc_sema::{
35 Base, Const, DeclId, DeclKind, Definition, Eval, ExprId, ExprKind, InitEntry, InitList,
36 Linkage, StorageDuration, StrId, Tast,
37};
38use rucc_target::TargetInfo;
39use rucc_types::{TypeId, TypeKind, Types};
40
41use crate::abi::{self, Plan};
42use crate::body;
43use crate::repr;
44
45#[derive(Debug)]
50pub struct Context<'a> {
51 pub tast: &'a Tast,
53 pub types: &'a Types,
55 pub target: &'a TargetInfo,
57 pub names: &'a mut Interner,
59}
60
61#[derive(Debug)]
63pub struct Lowered {
64 pub module: Module,
67 pub diagnostics: Vec<Diagnostic>,
69}
70
71#[must_use]
75pub fn lower(name: &str, cx: Context<'_>) -> Lowered {
76 let Context { tast, types, target, names } = cx;
77 let module = Module::new(names.intern(name), target);
78 let mut unit = Unit {
79 tast,
80 types,
81 target,
82 names,
83 module,
84 diagnostics: Vec::new(),
85 strings: HashMap::new(),
86 statics: HashMap::new(),
87 done: HashSet::new(),
88 };
89 unit.run();
90 Lowered { module: unit.module, diagnostics: unit.diagnostics }
91}
92
93pub(crate) struct Unit<'a> {
95 pub(crate) tast: &'a Tast,
96 pub(crate) types: &'a Types,
97 pub(crate) target: &'a TargetInfo,
98 pub(crate) names: &'a mut Interner,
99 pub(crate) module: Module,
100 pub(crate) diagnostics: Vec<Diagnostic>,
101 strings: HashMap<StrId, Symbol>,
104 statics: HashMap<DeclId, Symbol>,
106 done: HashSet<DeclId>,
108}
109
110impl std::fmt::Debug for Unit<'_> {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 f.debug_struct("Unit")
115 .field("module", &self.module.counts())
116 .field("diagnostics", &self.diagnostics.len())
117 .finish()
118 }
119}
120
121impl Unit<'_> {
122 fn run(&mut self) {
124 for index in 0..self.tast.top_level().len() {
125 let decl = self.tast.top_level()[index];
126 if !self.done.insert(decl) {
127 continue;
128 }
129 match self.tast[decl].kind {
130 DeclKind::Function => self.function(decl),
131 DeclKind::Object => self.object(decl),
132 }
133 }
134 }
135
136 fn object(&mut self, decl: DeclId) {
138 let tast = self.tast;
139 let node = &tast[decl];
140 let (ty, state, init) = (node.ty, node.state, node.init);
141 let (linkage, duration, alignment) = (node.linkage, node.duration, node.alignment);
142 let span = tast.decl_span(decl);
143 if duration == StorageDuration::Automatic {
144 return;
147 }
148
149 let symbol = self.symbol_of(decl);
150 let size = repr::size_of(self.types, self.target, ty);
151 let align = alignment.unwrap_or_else(|| repr::align_of(self.types, self.target, ty));
152 let mut global = Global::new(symbol, size, align);
153 global.linkage = match linkage {
154 Linkage::External => IrLinkage::External,
155 Linkage::Internal | Linkage::None => IrLinkage::Internal,
156 };
157 global.tls = (duration == StorageDuration::Thread).then_some(TlsModel::GlobalDynamic);
158 global.constant = repr::is_read_only(self.types, ty);
159 global.init = match state {
160 Definition::Declared => None,
164 Definition::Tentative => Some(self.zeros(size)),
165 Definition::Defined => Some(self.image(init, size, span)),
166 };
167 self.module.add_global(global);
168 }
169
170 fn function(&mut self, decl: DeclId) {
172 let tast = self.tast;
173 let node = &tast[decl];
174 let (ty, linkage, body) = (node.ty, node.linkage, node.body);
175 let span = tast.decl_span(decl);
176 let Some(name) = node.name else { return };
177 let Some(plan) = self.plan(ty, &[], span) else { return };
178
179 let mut func = Func::new(name, plan.signature.clone());
180 func.linkage = match linkage {
181 Linkage::Internal | Linkage::None => IrLinkage::Internal,
182 Linkage::External => IrLinkage::External,
183 };
184 if body.is_some() {
185 body::lower(self, decl, &mut func, &plan);
186 }
187 self.module.add_func(func);
188 }
189
190 pub(crate) fn plan(&mut self, ty: TypeId, actual: &[TypeId], span: Span) -> Option<Plan> {
197 let canonical = self.types.canonical(ty);
198 let canonical = match self.types.kind(canonical) {
199 TypeKind::Pointer(pointee) => self.types.canonical(pointee),
201 _ => canonical,
202 };
203 let TypeKind::Function(id) = self.types.kind(canonical) else {
204 self.unsupported("a call through something that is not a function", span);
205 return None;
206 };
207 let signature = self.types.signature(id);
208 let ret = signature.ret;
209 let variadic = signature.variadic || !signature.prototyped;
213 let params = signature.params.clone();
214
215 match abi::plan(self.types, self.target, ret, ¶ms, actual, variadic) {
216 Ok(plan) => Some(plan),
217 Err(what) => {
218 self.unsupported(what, span);
219 None
220 }
221 }
222 }
223
224 pub(crate) fn image(&mut self, init: Option<InitList>, size: u64, span: Span) -> DataList {
226 let Some(init) = init else { return self.zeros(size) };
227 let entries: Vec<InitEntry> = self.tast[init].to_vec();
228 let mut packed = self.packed(&entries, size);
229 let mut data: Vec<Datum> = Vec::with_capacity(entries.len());
230 let mut at = 0;
231 for entry in entries {
232 let Some(datum) = self.entry(entry, &mut packed, size) else { continue };
233 match entry.offset.cmp(&at) {
234 Ordering::Greater => data.push(Datum::Zero(entry.offset - at)),
235 Ordering::Less => {
239 self.unsupported("an initializer that writes over an earlier one", span);
240 continue;
241 }
242 Ordering::Equal => {}
243 }
244 at = entry.offset + datum.size(&self.module);
245 data.push(datum);
246 }
247 if at < size {
248 data.push(Datum::Zero(size - at));
251 }
252 self.module.push_data(&data)
253 }
254
255 fn entry(
262 &mut self,
263 entry: InitEntry,
264 packed: &mut BTreeMap<u64, u8>,
265 size: u64,
266 ) -> Option<Datum> {
267 if entry.is_bit_field() {
268 let bytes = take_run(packed, entry.offset)?;
269 return Some(Datum::Bytes(self.module.push_bytes(&bytes)));
270 }
271 let room = size.saturating_sub(entry.offset);
272 self.datum(entry.value, room)
273 }
274
275 fn packed(&mut self, entries: &[InitEntry], size: u64) -> BTreeMap<u64, u8> {
280 let mut bytes = BTreeMap::new();
281 for entry in entries.iter().filter(|entry| entry.is_bit_field()) {
282 let Some(folded) = self.fold(entry.value) else { continue };
283 let Const::Int(number) = folded else {
284 let span = self.tast.expr_span(entry.value);
285 let what = "a bit-field initialized by something that is not an integer";
286 self.unsupported(what, span);
287 continue;
288 };
289 let width = entry.bit_width;
290 let ones = if width >= 128 { u128::MAX } else { (1u128 << width) - 1 };
291 let mut placed = ((number as u128) & ones) << entry.bit_offset;
292 let mut at = entry.offset;
293 while placed != 0 && at < size {
294 *bytes.entry(at).or_insert(0) |= (placed & 0xff) as u8;
295 placed >>= 8;
296 at += 1;
297 }
298 }
299 bytes
300 }
301
302 fn datum(&mut self, value: ExprId, room: u64) -> Option<Datum> {
304 let tast = self.tast;
305 let ty = tast[value].ty;
306 let span = tast.expr_span(value);
307 if let TypeKind::Array { .. } = self.types.kind(self.types.canonical(ty)) {
308 let ExprKind::Str(id) = tast[value].kind else {
312 self.unsupported("this initializer", span);
313 return None;
314 };
315 let bytes = tast[id].bytes(self.target);
316 let take = bytes.len().min(usize::try_from(room).unwrap_or(usize::MAX));
317 return Some(Datum::Bytes(self.module.push_bytes(&bytes[..take])));
318 }
319
320 let size = repr::size_of(self.types, self.target, ty);
321 match self.fold(value)? {
322 Const::Int(number) => {
323 let ty = repr::value_type(self.types, self.target, ty)?;
324 let imm = self.module.add_imm(Imm::int(number, ty));
325 Some(Datum::Scalar { ty, value: imm })
326 }
327 Const::Float(number) => {
328 let ty = repr::value_type(self.types, self.target, ty)?;
329 let imm = self.module.add_imm(Imm::from_bits(number.to_bits()));
330 Some(Datum::Scalar { ty, value: imm })
331 }
332 Const::Address(address) => {
333 let symbol = match address.base {
334 Base::Decl(decl) => self.symbol_of(decl),
335 Base::Str(id) => self.string(id),
336 };
337 let addend = i64::try_from(address.offset).unwrap_or(0);
338 let size = u32::try_from(size).unwrap_or(0);
339 Some(Datum::Addr(self.module.add_reloc(Reloc { symbol, addend, size })))
340 }
341 }
342 }
343
344 fn zeros(&mut self, size: u64) -> DataList {
346 if size == 0 {
347 return DataList::EMPTY;
348 }
349 self.module.push_data(&[Datum::Zero(size)])
350 }
351
352 pub(crate) fn string(&mut self, id: StrId) -> Symbol {
354 if let Some(&symbol) = self.strings.get(&id) {
355 return symbol;
356 }
357 let literal = &self.tast[id];
358 let bytes = literal.bytes(self.target);
359 let align = literal.encoding.element_width(self.target) / 8;
360 let symbol = self.names.intern(&format!(".Lstr.{}", self.strings.len()));
361
362 let mut global = Global::new(symbol, bytes.len() as u64, align.max(1));
363 global.linkage = IrLinkage::Internal;
364 global.constant = true;
368 let range = self.module.push_bytes(&bytes);
369 global.init = Some(self.module.push_data(&[Datum::Bytes(range)]));
370 self.module.add_global(global);
371 self.strings.insert(id, symbol);
372 symbol
373 }
374
375 pub(crate) fn symbol_of(&mut self, decl: DeclId) -> Symbol {
377 let tast = self.tast;
378 let node = &tast[decl];
379 if node.linkage != Linkage::None {
380 return node.name.unwrap_or_else(|| self.names.intern(".Lanon"));
381 }
382 if let Some(&symbol) = self.statics.get(&decl) {
383 return symbol;
384 }
385 let base = match node.name {
388 Some(name) => self.names.resolve(name).to_string(),
389 None => ".Lanon".to_string(),
390 };
391 let symbol = self.names.intern(&format!("{base}.{}", self.statics.len()));
392 self.statics.insert(decl, symbol);
393 symbol
394 }
395
396 pub(crate) fn local_static(&mut self, decl: DeclId) {
398 if !self.done.insert(decl) {
399 return;
400 }
401 match self.tast[decl].kind {
402 DeclKind::Function => self.function(decl),
405 DeclKind::Object => self.object(decl),
406 }
407 }
408
409 fn fold(&mut self, expr: ExprId) -> Option<Const> {
411 let mut eval = Eval::new(self.tast, self.types, self.target, self.names);
412 let folded = eval.constant(expr);
413 let reported = eval.finish();
414 self.diagnostics.extend(reported);
415 match folded {
416 Ok(value) => Some(value),
417 Err(stop) => {
418 if !stop.poisoned {
419 let span = self.tast.expr_span(stop.at);
420 self.unsupported("an initializer this compiler cannot fold", span);
421 }
422 None
423 }
424 }
425 }
426
427 pub(crate) fn unsupported(&mut self, what: &str, span: Span) {
429 self.diagnostics.push(
430 Diagnostic::error(format!("{what} is not supported yet"), span).with_code("E0519"),
431 );
432 }
433}
434
435fn take_run(bytes: &mut BTreeMap<u64, u8>, start: u64) -> Option<Vec<u8>> {
440 let mut run = vec![bytes.remove(&start)?];
441 let mut at = start + 1;
442 while let Some(byte) = bytes.remove(&at) {
443 run.push(byte);
444 at += 1;
445 }
446 Some(run)
447}