Try add some display for LLIR

This commit is contained in:
Sofia 2025-07-21 12:07:42 +03:00
parent f55040ad00
commit 1ba1ae3213
8 changed files with 295 additions and 17 deletions

View File

@ -67,7 +67,7 @@ pub struct InstructionHolder {
#[derive(Clone)]
pub(crate) struct Builder {
modules: Rc<RefCell<Vec<ModuleHolder>>>,
pub(crate) modules: Rc<RefCell<Vec<ModuleHolder>>>,
pub(crate) producer: String,
}
@ -368,7 +368,6 @@ impl Builder {
}
Instr::FunctionCall(fun, params) => {
let param_types = self.function_data(&fun).params;
dbg!(&param_types, &params);
if param_types.len() != params.len() {
return Err(()); // TODO error: invalid amount of params
}

View File

@ -339,7 +339,7 @@ impl ModuleHolder {
debug.locations.insert(location.value, location_ref);
}
for meta in debug.debug.get_metadata().borrow().iter() {
for meta in debug.debug.get_metadatas().borrow().iter() {
let meta_ref = meta.compile(&debug);
debug.metadata.insert(meta.value.clone(), meta_ref);
}
@ -606,7 +606,7 @@ impl FunctionHolder {
let metadata = if let Some(debug) = debug {
if let Some(value) = &self.data.debug {
let subprogram = debug.debug.get_subprogram_data(&value);
let subprogram = debug.debug.get_subprogram_data_unchecked(&value);
let mangled_length_ptr = &mut 0;
let mangled_name = LLVMGetValueName2(function_ref, mangled_length_ptr);

View File

@ -1,4 +1,4 @@
use std::{cell::RefCell, rc::Rc};
use std::{cell::RefCell, collections::hash_map::Values, rc::Rc};
use crate::builder::InstructionValue;
@ -161,7 +161,33 @@ impl DebugInformation {
value
}
pub fn get_metadata(&self) -> Rc<RefCell<Vec<DebugMetadataHolder>>> {
pub fn get_metadata(&self, value: DebugMetadataValue) -> DebugMetadata {
unsafe { self.metadata.borrow().get_unchecked(value.0).data.clone() }
}
pub fn get_subprogram_data(&self, value: DebugProgramValue) -> Option<DebugSubprogramData> {
if value.0 == 0 {
None
} else {
Some(self.get_subprogram_data_unchecked(&value))
}
}
pub fn get_type_data(&self, value: DebugTypeValue) -> DebugTypeData {
unsafe { self.types.borrow().get_unchecked(value.0).data.clone() }
}
pub fn get_location(&self, value: DebugLocationValue) -> DebugLocation {
unsafe {
self.locations
.borrow()
.get_unchecked(value.1)
.location
.clone()
}
}
pub fn get_metadatas(&self) -> Rc<RefCell<Vec<DebugMetadataHolder>>> {
self.metadata.clone()
}
@ -181,7 +207,7 @@ impl DebugInformation {
self.locations.clone()
}
pub fn get_subprogram_data(&self, value: &DebugProgramValue) -> DebugSubprogramData {
pub fn get_subprogram_data_unchecked(&self, value: &DebugProgramValue) -> DebugSubprogramData {
unsafe {
self.programs
.borrow()

View File

@ -1,20 +1,187 @@
//! Debug implementations for relevant types
use std::{
fmt::{Debug, Write},
fmt::{Debug, Display, Write},
marker::PhantomData,
};
use crate::{
CmpPredicate, Instr, InstructionData, TerminatorKind,
CmpPredicate, Context, Instr, InstructionData, TerminatorKind,
builder::*,
debug_information::{
DebugArrayType, DebugBasicType, DebugFieldType, DebugLocation, DebugLocationValue,
DebugMetadataValue, DebugPointerType, DebugProgramValue, DebugScopeValue, DebugStructType,
DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocalVariable,
DebugLocation, DebugLocationValue, DebugMetadata, DebugMetadataValue, DebugParamVariable,
DebugPointerType, DebugProgramValue, DebugRecordKind, DebugScopeValue, DebugStructType,
DebugSubprogramType, DebugTypeData, DebugTypeHolder, DebugTypeValue,
},
pad_adapter::PadAdapter,
};
impl Display for Context {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.builder, f)
}
}
impl Display for Builder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Producer: {}", self.producer)?;
for module in self.modules.borrow().iter() {
if module.data.is_main {
write!(f, "main ")?;
}
writeln!(f, "{} ({:?}) {{", module.data.name, module.value)?;
for function in &module.functions {
let mut state = Default::default();
let mut inner = PadAdapter::wrap(f, &mut state);
function.builder_fmt(&mut inner, self, &module.debug_information)?;
}
writeln!(f, "}}")?;
}
Ok(())
}
}
impl FunctionHolder {
fn builder_fmt(
&self,
f: &mut impl std::fmt::Write,
builder: &Builder,
debug: &Option<DebugInformation>,
) -> std::fmt::Result {
if self.data.flags.is_imported {
write!(f, "imported ")?;
}
if self.data.flags.is_extern {
write!(f, "extern ")?;
}
if self.data.flags.is_pub {
write!(f, "pub ")?;
}
if self.data.flags.is_main {
write!(f, "main ")?;
}
let params = self
.data
.params
.iter()
.map(|p| format!("{:?}", p))
.collect::<Vec<_>>()
.join(", ");
write!(
f,
"fn {}({}) -> {:?} ",
self.data.name, params, self.data.ret
)?;
writeln!(f, "{{")?;
let mut state = Default::default();
let mut inner = PadAdapter::wrap(f, &mut state);
writeln!(inner, "(Value = {:?}) ", self.value)?;
if let Some(debug) = self.data.debug {
writeln!(inner, "(Debug = {:?})", debug)?;
}
for block in &self.blocks {
let mut state = Default::default();
let mut inner = PadAdapter::wrap(&mut inner, &mut state);
block.builder_fmt(&mut inner, builder, debug)?;
}
writeln!(f, "}}")?;
Ok(())
}
}
impl BlockHolder {
fn builder_fmt(
&self,
f: &mut impl std::fmt::Write,
builder: &Builder,
debug: &Option<DebugInformation>,
) -> std::fmt::Result {
if self.data.deleted {
write!(f, "deleted ")?;
}
writeln!(f, "{} ({:?}):", self.data.name, self.value)?;
for instr in &self.instructions {
let mut state = Default::default();
let mut inner = PadAdapter::wrap(f, &mut state);
instr.builder_fmt(&mut inner, builder, debug)?;
}
Ok(())
}
}
impl InstructionHolder {
fn builder_fmt(
&self,
f: &mut impl std::fmt::Write,
builder: &Builder,
debug: &Option<DebugInformation>,
) -> std::fmt::Result {
if let Some(record) = &self.record {
let kind = match record.kind {
DebugRecordKind::Declare(instruction_value) => {
format!("= {:?} (Assign)", instruction_value)
}
DebugRecordKind::Value(instruction_value) => {
format!("= {:?} (Value)", instruction_value)
}
};
if let Some(debug) = debug {
writeln!(f, " (Debug {} {})", record.variable.hr(debug), kind)?;
}
}
writeln!(
f,
"{:?} ({}) = {:?} ",
self.value, self.name, self.data.kind
)?;
if let Some(debug) = debug {
if let Some(location) = self.data.location {
writeln!(f, " ^ (At {}) ", debug.get_location(location))?;
}
if let Some(meta) = self.data.meta {
writeln!(f, " ^ (Meta {}) ", meta.hr(debug))?;
}
}
writeln!(f)?;
Ok(())
}
}
impl DebugMetadataValue {
fn hr(&self, debug: &DebugInformation) -> String {
match debug.get_metadata(*self) {
DebugMetadata::ParamVar(DebugParamVariable {
name,
arg_idx,
location,
ty,
..
}) => format!(
"param {} (idx {}) (type {:?}) at {}",
name, arg_idx, ty, location
),
DebugMetadata::LocalVar(DebugLocalVariable {
name, location, ty, ..
}) => format!("var {} (type {:?}) at {}", name, ty, location),
DebugMetadata::VarAssignment => todo!(),
}
}
}
impl Display for DebugLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "line {}, col {}", self.line, self.column)
}
}
impl Debug for Builder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_list().entries(self.get_modules().borrow().iter());
@ -29,7 +196,7 @@ pub struct PrintableModule<'ctx> {
impl<'ctx> Debug for PrintableModule<'ctx> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.module.fmt(f)
Debug::fmt(&self.module, f)
}
}
@ -108,12 +275,22 @@ impl Debug for InstructionValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"I[{:0>2}-{:0>2}-{:0>2}-{:0>2}]",
&self.0.0.0.0, &self.0.0.1, &self.0.1, self.1
"%{}.{}.{}.{}",
self.0.0.0.0, self.0.0.1, self.0.1, self.1
)
}
}
// impl Debug for InstructionValue {
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// write!(
// f,
// "I[{:0>2}-{:0>2}-{:0>2}-{:0>2}]",
// &self.0.0.0.0, &self.0.0.1, &self.0.1, self.1
// )
// }
// }
impl Debug for TypeValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Ty[{:0>2}-{:0>2}]", &self.0.0, self.1)

View File

@ -16,6 +16,7 @@ pub mod builder;
pub mod compile;
pub mod debug_information;
mod fmt;
mod pad_adapter;
mod util;
#[derive(Debug)]

View File

@ -0,0 +1,69 @@
//! Copied from
//! https://github.com/rust-lang/rust/blob/6b3ae3f6e45a33c2d95fa0362c9b2593e567fd34/library/core/src/fmt/builders.rs#L102
// Copyright (c) The Rust Project Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
use std::fmt;
pub struct PadAdapter<'buf, 'state> {
buf: &'buf mut (dyn fmt::Write + 'buf),
state: &'state mut PadAdapterState,
}
pub struct PadAdapterState {
on_newline: bool,
}
impl Default for PadAdapterState {
fn default() -> Self {
PadAdapterState { on_newline: true }
}
}
impl<'buf, 'state> PadAdapter<'buf, 'state> {
pub fn wrap<'slot, 'fmt: 'buf + 'slot>(
fmt: &'buf mut (dyn fmt::Write + 'buf),
state: &'state mut PadAdapterState,
) -> Self {
PadAdapter { buf: fmt, state }
}
}
impl fmt::Write for PadAdapter<'_, '_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
for s in s.split_inclusive('\n') {
if self.state.on_newline {
self.buf.write_str(" ")?;
}
self.state.on_newline = s.ends_with('\n');
self.buf.write_str(s)?;
}
Ok(())
}
fn write_char(&mut self, c: char) -> fmt::Result {
if self.state.on_newline {
self.buf.write_str(" ")?;
}
self.state.on_newline = c == '\n';
self.buf.write_char(c)
}
}

View File

@ -27,7 +27,7 @@ use crate::{
/// LLIR that can then be finally compiled into LLVM IR.
#[derive(Debug)]
pub struct CodegenContext<'ctx> {
context: &'ctx Context,
pub(crate) context: &'ctx Context,
}
impl<'ctx> CodegenContext<'ctx> {

View File

@ -123,6 +123,8 @@ pub fn perform_all_passes<'map>(
let state = context.pass(&mut LinkerPass { module_map })?;
#[cfg(debug_assertions)]
println!("{:-^100}", "LINKER OUTPUT");
#[cfg(debug_assertions)]
println!("{}", &context);
#[cfg(debug_assertions)]
@ -139,6 +141,8 @@ pub fn perform_all_passes<'map>(
let state = context.pass(&mut TypeInference { refs: &refs })?;
#[cfg(debug_assertions)]
println!("{:-^100}", "TYPE INFERRER OUTPUT");
#[cfg(debug_assertions)]
dbg!(&refs);
#[cfg(debug_assertions)]
@ -159,6 +163,8 @@ pub fn perform_all_passes<'map>(
let state = context.pass(&mut TypeCheck { refs: &refs })?;
#[cfg(debug_assertions)]
println!("{:-^100}", "TYPECHECKER OUTPUT");
#[cfg(debug_assertions)]
println!("{}", &context);
#[cfg(debug_assertions)]
@ -197,7 +203,7 @@ pub fn compile_and_pass<'map>(
perform_all_passes(&mut mir_context, module_map)?;
#[cfg(debug_assertions)]
dbg!(&mir_context);
println!("{:-^100}", "FINAL OUTPUT");
#[cfg(debug_assertions)]
println!("{}", &mir_context);
@ -205,7 +211,7 @@ pub fn compile_and_pass<'map>(
let codegen_modules = mir_context.codegen(&mut context, &module_map);
#[cfg(debug_assertions)]
dbg!(&codegen_modules);
println!("{}", &codegen_modules.context);
let compiled = codegen_modules.compile();
Ok(compiled.output())