1use std::cmp::Ordering;
29use std::collections::{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, Signature, TlsModel,
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::body;
44use crate::repr;
45
46#[derive(Debug)]
51pub struct Context<'a> {
52 pub tast: &'a Tast,
54 pub types: &'a Types,
56 pub target: &'a TargetInfo,
58 pub names: &'a mut Interner,
60}
61
62#[derive(Debug)]
64pub struct Lowered {
65 pub module: Module,
68 pub diagnostics: Vec<Diagnostic>,
70}
71
72#[must_use]
76pub fn lower(name: &str, cx: Context<'_>) -> Lowered {
77 let Context { tast, types, target, names } = cx;
78 let module = Module::new(names.intern(name), target);
79 let mut unit = Unit {
80 tast,
81 types,
82 target,
83 names,
84 module,
85 diagnostics: Vec::new(),
86 strings: HashMap::new(),
87 statics: HashMap::new(),
88 done: HashSet::new(),
89 };
90 unit.run();
91 Lowered { module: unit.module, diagnostics: unit.diagnostics }
92}
93
94pub(crate) struct Unit<'a> {
96 pub(crate) tast: &'a Tast,
97 pub(crate) types: &'a Types,
98 pub(crate) target: &'a TargetInfo,
99 pub(crate) names: &'a mut Interner,
100 pub(crate) module: Module,
101 pub(crate) diagnostics: Vec<Diagnostic>,
102 strings: HashMap<StrId, Symbol>,
105 statics: HashMap<DeclId, Symbol>,
107 done: HashSet<DeclId>,
109}
110
111impl std::fmt::Debug for Unit<'_> {
114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 f.debug_struct("Unit")
116 .field("module", &self.module.counts())
117 .field("diagnostics", &self.diagnostics.len())
118 .finish()
119 }
120}
121
122impl Unit<'_> {
123 fn run(&mut self) {
125 for index in 0..self.tast.top_level().len() {
126 let decl = self.tast.top_level()[index];
127 if !self.done.insert(decl) {
128 continue;
129 }
130 match self.tast[decl].kind {
131 DeclKind::Function => self.function(decl),
132 DeclKind::Object => self.object(decl),
133 }
134 }
135 }
136
137 fn object(&mut self, decl: DeclId) {
139 let tast = self.tast;
140 let node = &tast[decl];
141 let (ty, state, init) = (node.ty, node.state, node.init);
142 let (linkage, duration, alignment) = (node.linkage, node.duration, node.alignment);
143 let span = tast.decl_span(decl);
144 if duration == StorageDuration::Automatic {
145 return;
148 }
149
150 let symbol = self.symbol_of(decl);
151 let size = repr::size_of(self.types, self.target, ty);
152 let align = alignment.unwrap_or_else(|| repr::align_of(self.types, self.target, ty));
153 let mut global = Global::new(symbol, size, align);
154 global.linkage = match linkage {
155 Linkage::External => IrLinkage::External,
156 Linkage::Internal | Linkage::None => IrLinkage::Internal,
157 };
158 global.tls = (duration == StorageDuration::Thread).then_some(TlsModel::GlobalDynamic);
159 global.constant = repr::is_read_only(self.types, ty);
160 global.init = match state {
161 Definition::Declared => None,
165 Definition::Tentative => Some(self.zeros(size)),
166 Definition::Defined => Some(self.image(init, size, span)),
167 };
168 self.module.add_global(global);
169 }
170
171 fn function(&mut self, decl: DeclId) {
173 let tast = self.tast;
174 let node = &tast[decl];
175 let (ty, linkage, body) = (node.ty, node.linkage, node.body);
176 let span = tast.decl_span(decl);
177 let Some(name) = node.name else { return };
178 let Some(signature) = self.signature(ty, span) else { return };
179
180 let mut func = Func::new(name, signature);
181 func.linkage = match linkage {
182 Linkage::Internal | Linkage::None => IrLinkage::Internal,
183 Linkage::External => IrLinkage::External,
184 };
185 if body.is_some() {
186 body::lower(self, decl, &mut func);
187 }
188 self.module.add_func(func);
189 }
190
191 pub(crate) fn signature(&mut self, ty: TypeId, span: Span) -> Option<Signature> {
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, variadic) = (signature.ret, signature.variadic);
209 let prototyped = signature.prototyped;
210 let params = signature.params.clone();
211
212 let mut lowered = Signature::new();
213 lowered.variadic = variadic || !prototyped;
217 for param in params {
218 match repr::value_type(self.types, self.target, param) {
219 Some(ty) => lowered.params.push(ty),
220 None => {
221 self.unsupported("passing a structure or a union by value", span);
222 return None;
223 }
224 }
225 }
226 if !matches!(self.types.kind(self.types.canonical(ret)), TypeKind::Void) {
227 match repr::value_type(self.types, self.target, ret) {
228 Some(ty) => lowered.returns.push(ty),
229 None => {
230 self.unsupported("returning a structure or a union by value", span);
231 return None;
232 }
233 }
234 }
235 Some(lowered)
236 }
237
238 pub(crate) fn image(&mut self, init: Option<InitList>, size: u64, span: Span) -> DataList {
240 let Some(init) = init else { return self.zeros(size) };
241 let entries: Vec<InitEntry> = self.tast[init].to_vec();
242 let mut data: Vec<Datum> = Vec::with_capacity(entries.len());
243 let mut at = 0;
244 for entry in entries {
245 if entry.bit_width != 0 {
246 self.unsupported("a bit-field with a static storage duration", span);
247 continue;
248 }
249 let room = size.saturating_sub(entry.offset);
250 let Some(datum) = self.datum(entry.value, room) else { continue };
251 match entry.offset.cmp(&at) {
252 Ordering::Greater => data.push(Datum::Zero(entry.offset - at)),
253 Ordering::Less => {
257 self.unsupported("an initializer that writes over an earlier one", span);
258 continue;
259 }
260 Ordering::Equal => {}
261 }
262 at = entry.offset + datum.size(&self.module);
263 data.push(datum);
264 }
265 if at < size {
266 data.push(Datum::Zero(size - at));
269 }
270 self.module.push_data(&data)
271 }
272
273 fn datum(&mut self, value: ExprId, room: u64) -> Option<Datum> {
275 let tast = self.tast;
276 let ty = tast[value].ty;
277 let span = tast.expr_span(value);
278 if let TypeKind::Array { .. } = self.types.kind(self.types.canonical(ty)) {
279 let ExprKind::Str(id) = tast[value].kind else {
283 self.unsupported("this initializer", span);
284 return None;
285 };
286 let bytes = tast[id].bytes(self.target);
287 let take = bytes.len().min(usize::try_from(room).unwrap_or(usize::MAX));
288 return Some(Datum::Bytes(self.module.push_bytes(&bytes[..take])));
289 }
290
291 let size = repr::size_of(self.types, self.target, ty);
292 match self.fold(value)? {
293 Const::Int(number) => {
294 let ty = repr::value_type(self.types, self.target, ty)?;
295 let imm = self.module.add_imm(Imm::int(number, ty));
296 Some(Datum::Scalar { ty, value: imm })
297 }
298 Const::Float(number) => {
299 let ty = repr::value_type(self.types, self.target, ty)?;
300 let imm = self.module.add_imm(Imm::from_bits(number.to_bits()));
301 Some(Datum::Scalar { ty, value: imm })
302 }
303 Const::Address(address) => {
304 let symbol = match address.base {
305 Base::Decl(decl) => self.symbol_of(decl),
306 Base::Str(id) => self.string(id),
307 };
308 let addend = i64::try_from(address.offset).unwrap_or(0);
309 let size = u32::try_from(size).unwrap_or(0);
310 Some(Datum::Addr(self.module.add_reloc(Reloc { symbol, addend, size })))
311 }
312 }
313 }
314
315 fn zeros(&mut self, size: u64) -> DataList {
317 if size == 0 {
318 return DataList::EMPTY;
319 }
320 self.module.push_data(&[Datum::Zero(size)])
321 }
322
323 pub(crate) fn string(&mut self, id: StrId) -> Symbol {
325 if let Some(&symbol) = self.strings.get(&id) {
326 return symbol;
327 }
328 let literal = &self.tast[id];
329 let bytes = literal.bytes(self.target);
330 let align = literal.encoding.element_width(self.target) / 8;
331 let symbol = self.names.intern(&format!(".Lstr.{}", self.strings.len()));
332
333 let mut global = Global::new(symbol, bytes.len() as u64, align.max(1));
334 global.linkage = IrLinkage::Internal;
335 global.constant = true;
339 let range = self.module.push_bytes(&bytes);
340 global.init = Some(self.module.push_data(&[Datum::Bytes(range)]));
341 self.module.add_global(global);
342 self.strings.insert(id, symbol);
343 symbol
344 }
345
346 pub(crate) fn symbol_of(&mut self, decl: DeclId) -> Symbol {
348 let tast = self.tast;
349 let node = &tast[decl];
350 if node.linkage != Linkage::None {
351 return node.name.unwrap_or_else(|| self.names.intern(".Lanon"));
352 }
353 if let Some(&symbol) = self.statics.get(&decl) {
354 return symbol;
355 }
356 let base = match node.name {
359 Some(name) => self.names.resolve(name).to_string(),
360 None => ".Lanon".to_string(),
361 };
362 let symbol = self.names.intern(&format!("{base}.{}", self.statics.len()));
363 self.statics.insert(decl, symbol);
364 symbol
365 }
366
367 pub(crate) fn local_static(&mut self, decl: DeclId) {
369 if !self.done.insert(decl) {
370 return;
371 }
372 match self.tast[decl].kind {
373 DeclKind::Function => self.function(decl),
376 DeclKind::Object => self.object(decl),
377 }
378 }
379
380 fn fold(&mut self, expr: ExprId) -> Option<Const> {
382 let mut eval = Eval::new(self.tast, self.types, self.target, self.names);
383 let folded = eval.constant(expr);
384 let reported = eval.finish();
385 self.diagnostics.extend(reported);
386 match folded {
387 Ok(value) => Some(value),
388 Err(stop) => {
389 if !stop.poisoned {
390 let span = self.tast.expr_span(stop.at);
391 self.unsupported("an initializer this compiler cannot fold", span);
392 }
393 None
394 }
395 }
396 }
397
398 pub(crate) fn unsupported(&mut self, what: &str, span: Span) {
400 self.diagnostics.push(
401 Diagnostic::error(format!("{what} is not supported yet"), span).with_code("E0519"),
402 );
403 }
404}