Skip to content

Commit

Permalink
[llvm-context,solidity] Expand and use DebugInfo structure.
Browse files Browse the repository at this point in the history
- When the debug-info generation is enabled, construct a DebugInfo instance.

- Add a namespace stack to the DebugInfo structure to keep track of the
  names of named scopes, such as namespaces, objects and functions,
  enclosing a construct.
  • Loading branch information
wpt967 committed Oct 4, 2024
1 parent c54a5b9 commit c535b41
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 6 deletions.
1 change: 1 addition & 0 deletions crates/llvm-context/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub use self::polkavm::context::argument::Argument as PolkaVMArgument;
pub use self::polkavm::context::attribute::Attribute as PolkaVMAttribute;
pub use self::polkavm::context::build::Build as PolkaVMBuild;
pub use self::polkavm::context::code_type::CodeType as PolkaVMCodeType;
pub use self::polkavm::context::debug_info::DebugInfo;
pub use self::polkavm::context::evmla_data::EVMLAData as PolkaVMContextEVMLAData;
pub use self::polkavm::context::function::block::evmla_data::key::Key as PolkaVMFunctionBlockKey;
pub use self::polkavm::context::function::block::evmla_data::EVMLAData as PolkaVMFunctionBlockEVMLAData;
Expand Down
95 changes: 94 additions & 1 deletion crates/llvm-context/src/polkavm/context/debug_info.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,50 @@
//! The LLVM debug information.

use std::cell::RefCell;

use inkwell::debug_info::AsDIScope;
use inkwell::debug_info::DIScope;
use num::Zero;

/// Debug info scope stack
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ScopeStack<'ctx> {
stack: Vec<DIScope<'ctx>>,
}

// Abstract the type of the DIScope stack.
impl<'ctx> ScopeStack<'ctx> {
pub fn from(item: DIScope<'ctx>) -> Self {
Self { stack: vec![item] }
}

/// Return the top of the scope stack, or None if the stack is empty.
pub fn top(&self) -> Option<DIScope<'ctx>> {
self.stack.last().map(|rc| rc.clone())
}

/// Push a scope onto the stack.
pub fn push(&mut self, scope: DIScope<'ctx>) -> () {
self.stack.push(scope)
}

/// Pop the scope at the top of the stack and return it.
/// Return None if the stack is empty.
pub fn pop(&mut self) -> Option<DIScope<'ctx>> {
self.stack.pop()
}
}

/// The LLVM debug information.
pub struct DebugInfo<'ctx> {
/// The compile unit.
compile_unit: inkwell::debug_info::DICompileUnit<'ctx>,
/// The debug info builder.
builder: inkwell::debug_info::DebugInfoBuilder<'ctx>,
/// The debug info scope stack. Used when lowering to llvm-ir.
scope_stack: RefCell<ScopeStack<'ctx>>,
// Stack of names of enclosing objects, functions and other namespaces.
namespace_stack: RefCell<Vec<String>>,
}

impl<'ctx> DebugInfo<'ctx> {
Expand All @@ -35,6 +71,8 @@ impl<'ctx> DebugInfo<'ctx> {
Self {
compile_unit,
builder,
scope_stack: RefCell::new(ScopeStack::from(compile_unit.as_debug_info_scope())),
namespace_stack: RefCell::new(vec![]),
}
}

Expand All @@ -45,7 +83,7 @@ impl<'ctx> DebugInfo<'ctx> {
) -> anyhow::Result<inkwell::debug_info::DISubprogram<'ctx>> {
let subroutine_type = self.builder.create_subroutine_type(
self.compile_unit.get_file(),
Some(self.create_type(revive_common::BIT_LENGTH_FIELD)?),
Some(self.create_type(revive_common::BIT_LENGTH_WORD)?),
&[],
inkwell::debug_info::DIFlags::zero(),
);
Expand Down Expand Up @@ -94,4 +132,59 @@ impl<'ctx> DebugInfo<'ctx> {
pub fn finalize(&self) {
self.builder.finalize();
}

/// Return the DIBuilder.
pub fn builder(&self) -> &inkwell::debug_info::DebugInfoBuilder<'ctx> {
&self.builder
}

/// Return the compilation unit. {
pub fn compilation_unit(&self) -> &inkwell::debug_info::DICompileUnit<'ctx> {
&self.compile_unit
}

pub fn push_scope(&self, scope: DIScope<'ctx>) -> () {
self.scope_stack.borrow_mut().push(scope)
}

pub fn pop_scope(&self) -> Option<DIScope<'ctx>> {
self.scope_stack.borrow_mut().pop()
}

pub fn top_scope(&self) -> Option<DIScope<'ctx>> {
self.scope_stack.borrow().top()
}

pub fn push_namespace(&self, name: String) -> () {
self.namespace_stack.borrow_mut().push(name);
}

pub fn pop_namespace(&self) -> Option<String> {
self.namespace_stack.borrow_mut().pop()
}

pub fn top_namespace(&self) -> Option<String> {
self.namespace_stack.borrow().last().map(|rc| rc.clone())
}

// Get a string representation of the namespace stack. Optionally append the given name.
pub fn namespace_as_identifier(&self, name: Option<&str>) -> String {
let separator = '.';
let mut ret = String::new();
let mut sep = false;
for s in self.namespace_stack.borrow().iter() {
if sep {
ret.push(separator);
};
sep = true;
ret.push_str(s.as_str())
}
if let Some(n) = name {
if sep {
ret.push(separator);
};
ret.push_str(n);
}
ret
}
}
14 changes: 10 additions & 4 deletions crates/llvm-context/src/polkavm/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub mod argument;
pub mod attribute;
pub mod build;
pub mod code_type;
// pub mod debug_info;
pub mod debug_info;
pub mod evmla_data;
pub mod function;
pub mod global;
Expand Down Expand Up @@ -36,7 +36,7 @@ use self::address_space::AddressSpace;
use self::attribute::Attribute;
use self::build::Build;
use self::code_type::CodeType;
// use self::debug_info::DebugInfo;
use self::debug_info::DebugInfo;
use self::evmla_data::EVMLAData;
use self::function::declaration::Declaration as FunctionDeclaration;
use self::function::intrinsics::Intrinsics;
Expand Down Expand Up @@ -86,7 +86,7 @@ where
/// Whether to append the metadata hash at the end of bytecode.
include_metadata_hash: bool,
/// The debug info of the current module.
// debug_info: DebugInfo<'ctx>,
debug_info: Option<DebugInfo<'ctx>>,
/// The debug configuration telling whether to dump the needed IRs.
debug_config: Option<DebugConfig>,

Expand Down Expand Up @@ -196,6 +196,7 @@ where
optimizer: Optimizer,
dependency_manager: Option<D>,
include_metadata_hash: bool,
debug_info: Option<DebugInfo<'ctx>>,
debug_config: Option<DebugConfig>,
) -> Self {
Self::link_stdlib_module(llvm, &module);
Expand All @@ -221,7 +222,7 @@ where

dependency_manager,
include_metadata_hash,
// debug_info,
debug_info,
debug_config,

solidity_data: None,
Expand Down Expand Up @@ -574,6 +575,11 @@ where
.expect("The dependency manager is unset")
}

/// Returns the debug info.
pub fn debug_info(&self) -> Option<&DebugInfo> {
self.debug_info.as_ref()
}

/// Returns the debug config reference.
pub fn debug_config(&self) -> Option<&DebugConfig> {
self.debug_config.as_ref()
Expand Down
2 changes: 1 addition & 1 deletion crates/llvm-context/src/polkavm/context/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn create_context(
let module = llvm.create_module("test");
let optimizer = Optimizer::new(optimizer_settings);

Context::<DummyDependency>::new(llvm, module, optimizer, None, true, None)
Context::<DummyDependency>::new(llvm, module, optimizer, None, true, None, None)
}

#[test]
Expand Down
19 changes: 19 additions & 0 deletions crates/solidity/src/project/contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use revive_llvm_context::PolkaVMWriteLLVM;
use crate::build::contract::Contract as ContractBuild;
use crate::project::Project;
use crate::solc::version::Version as SolcVersion;
use revive_llvm_context::DebugInfo;

use self::ir::IR;
use self::metadata::Metadata;
Expand Down Expand Up @@ -83,6 +84,7 @@ impl Contract {
debug_config: Option<revive_llvm_context::DebugConfig>,
) -> anyhow::Result<ContractBuild> {
let llvm = inkwell::context::Context::create();
let emit_debug_info = optimizer_settings.emit_debug_info();
let optimizer = revive_llvm_context::Optimizer::new(optimizer_settings);

let version = project.version.clone();
Expand All @@ -106,6 +108,7 @@ impl Contract {

let module = match self.ir {
IR::LLVMIR(ref llvm_ir) => {
// Create the output module
let memory_buffer =
inkwell::memory_buffer::MemoryBuffer::create_from_memory_range_copy(
llvm_ir.source.as_bytes(),
Expand All @@ -116,12 +119,28 @@ impl Contract {
}
_ => llvm.create_module(self.path.as_str()),
};

let debug_info = if emit_debug_info {
let debug_metadata_value = llvm
.i32_type()
.const_int(inkwell::debug_info::debug_metadata_version() as u64, false);
module.add_basic_value_flag(
"Debug Info Version",
inkwell::module::FlagBehavior::Warning,
debug_metadata_value,
);
Some(DebugInfo::new(&module))
} else {
None
};

let mut context = revive_llvm_context::PolkaVMContext::new(
&llvm,
module,
optimizer,
Some(project),
include_metadata_hash,
debug_info,
debug_config,
);
context.set_solidity_data(revive_llvm_context::PolkaVMContextSolidityData::default());
Expand Down

0 comments on commit c535b41

Please sign in to comment.