Skip to content

Commit

Permalink
refactor: codegen value store and load & add debug info for the entir…
Browse files Browse the repository at this point in the history
…e module

Signed-off-by: peefy <xpf6677@163.com>
  • Loading branch information
Peefy committed Mar 12, 2024
1 parent 03712ef commit 9d7d3d2
Show file tree
Hide file tree
Showing 14 changed files with 417 additions and 397 deletions.
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,5 @@ _a.out_*.*
# Compiler_base
.compiler_base

# LLVM
llvm*
llvm-*

# KCL mod lock file
!.mod.lock
25 changes: 25 additions & 0 deletions kclvm/compiler/src/codegen/llvm/backtrack.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright The KCL Authors. All rights reserved.

use super::context::LLVMCodeGenContext;
use crate::codegen::traits::BuilderMethods;
use inkwell::values::BasicValueEnum;

impl<'ctx> LLVMCodeGenContext<'ctx> {
pub(crate) fn update_backtrack_meta(
&self,
name: &str,
schema_value: BasicValueEnum<'ctx>,
) -> bool {
if let Some(backtrack_meta) = self.backtrack_meta.borrow_mut().as_mut() {
if name == backtrack_meta.target {
backtrack_meta.count += 1;
if backtrack_meta.count >= backtrack_meta.level {
backtrack_meta.stop = true;
self.ret(schema_value);
return true;
}
}
}
false
}
}
188 changes: 114 additions & 74 deletions kclvm/compiler/src/codegen/llvm/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use indexmap::{IndexMap, IndexSet};
use inkwell::basic_block::BasicBlock;
use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::debug_info::{DICompileUnit, DebugInfoBuilder};
use inkwell::memory_buffer::MemoryBuffer;
use inkwell::module::{Linkage, Module};
use inkwell::support::LLVMString;
Expand All @@ -22,7 +23,6 @@ use std::rc::Rc;
use std::str;

use kclvm_ast::ast;
use kclvm_ast::walker::TypedResultWalker;
use kclvm_error::*;
use kclvm_runtime::{ApiFunc, MAIN_PKG_PATH, PKG_PATH_PREFIX};
use kclvm_sema::builtin;
Expand Down Expand Up @@ -61,12 +61,15 @@ pub struct Scope<'ctx> {
pub scalars: RefCell<Vec<BasicValueEnum<'ctx>>>,
/// schema_scalar_idx denotes whether a schema exists in the scalar list.
pub schema_scalar_idx: RefCell<usize>,
/// Scope normal variables
pub variables: RefCell<IndexMap<String, PointerValue<'ctx>>>,
/// Scope closures referenced by internal scope.
pub closures: RefCell<IndexMap<String, PointerValue<'ctx>>>,
/// Potential arguments in the current scope, such as schema/lambda arguments.
pub arguments: RefCell<IndexSet<String>>,
}

/// Schema internal order independent computation backtracking meta information.
/// Schema or Global internal order independent computation backtracking meta information.
pub struct BacktrackMeta {
pub target: String,
pub level: usize,
Expand All @@ -80,31 +83,50 @@ pub struct LLVMCodeGenContext<'ctx> {
pub module: Module<'ctx>,
pub builder: Builder<'ctx>,
pub program: &'ctx ast::Program,
pub pkg_scopes: RefCell<HashMap<String, Vec<Rc<Scope<'ctx>>>>>,
pub functions: RefCell<Vec<Rc<FunctionValue<'ctx>>>>,
pub imported: RefCell<HashSet<String>>,
pub local_vars: RefCell<HashSet<String>>,
pub schema_stack: RefCell<Vec<value::SchemaType>>,
pub lambda_stack: RefCell<Vec<usize>>,
pub schema_expr_stack: RefCell<Vec<()>>,
pub pkgpath_stack: RefCell<Vec<String>>,
pub filename_stack: RefCell<Vec<String>>,
/// Package scope to store variable pointers.
pub pkg_scopes: RefCell<HashMap<String, Vec<Rc<Scope<'ctx>>>>>,
/// Local variables in the loop.
pub local_vars: RefCell<HashSet<String>>,
/// The names of possible assignment objects for the current instruction.
pub target_vars: RefCell<Vec<String>>,
/// Global string caches
pub global_strings: RefCell<IndexMap<String, IndexMap<String, PointerValue<'ctx>>>>,
/// Global variable pointers cross different packages.
pub global_vars: RefCell<IndexMap<String, IndexMap<String, PointerValue<'ctx>>>>,
/// The filename of the source file corresponding to the current instruction
pub current_filename: RefCell<String>,
/// The line number of the source file corresponding to the current instruction
pub current_line: RefCell<u64>,
/// Error handler to store compile errors.
pub handler: RefCell<Handler>,
// Schema attr backtrack meta
/// Schema attr backtrack meta
pub backtrack_meta: RefCell<Option<BacktrackMeta>>,
/// Import names mapping
pub import_names: IndexMap<String, IndexMap<String, String>>,
// No link mode
/// No link mode
pub no_link: bool,
pub modules: RefCell<HashMap<String, RefCell<Module<'ctx>>>>,
/// Debug mode
pub debug: bool,
/// Program modules according to AST modules
pub modules: RefCell<HashMap<String, RefCell<DebugModule<'ctx>>>>,
/// Program workdir
pub workdir: String,
}

/// LLVM module with debug info builder and compile unit.
pub struct DebugModule<'ctx> {
pub inner: Module<'ctx>,
pub dibuilder: DebugInfoBuilder<'ctx>,
pub compile_unit: DICompileUnit<'ctx>,
}

impl<'ctx> CodeGenObject for BasicValueEnum<'ctx> {}

impl<'ctx> CodeGenObject for BasicTypeEnum<'ctx> {}
Expand Down Expand Up @@ -311,9 +333,9 @@ impl<'ctx> BuilderMethods for LLVMCodeGenContext<'ctx> {
fn lookup_function(&self, name: &str) -> Self::Function {
if self.no_link {
let pkgpath = self.current_pkgpath();
let modules = self.modules.borrow_mut();
let modules = self.modules.borrow();
let msg = format!("pkgpath {} is not found", pkgpath);
let module = modules.get(&pkgpath).expect(&msg).borrow_mut();
let module = &modules.get(&pkgpath).expect(&msg).borrow().inner;
if let Some(function) = module.get_function(name) {
function
} else {
Expand All @@ -337,7 +359,7 @@ impl<'ctx> BuilderMethods for LLVMCodeGenContext<'ctx> {
let pkgpath = self.current_pkgpath();
let msg = format!("pkgpath {} is not found", pkgpath);
let modules = self.modules.borrow_mut();
let module = modules.get(&pkgpath).expect(&msg).borrow_mut();
let module = &modules.get(&pkgpath).expect(&msg).borrow_mut().inner;
module.add_function(name, fn_ty, None)
} else {
self.module.add_function(name, fn_ty, None)
Expand Down Expand Up @@ -548,7 +570,7 @@ impl<'ctx> ValueMethods for LLVMCodeGenContext<'ctx> {
let pkgpath = self.current_pkgpath();
let modules = self.modules.borrow_mut();
let msg = format!("pkgpath {} is not found", pkgpath);
let module = modules.get(&pkgpath).expect(&msg).borrow_mut();
let module = &modules.get(&pkgpath).expect(&msg).borrow_mut().inner;
let fn_type = function.get_type();
function = module.add_function(function_name, fn_type, Some(Linkage::External));
}
Expand All @@ -562,7 +584,7 @@ impl<'ctx> ValueMethods for LLVMCodeGenContext<'ctx> {
let pkgpath = self.current_pkgpath();
let msg = format!("pkgpath {} is not found", pkgpath);
let modules = self.modules.borrow_mut();
let module = modules.get(&pkgpath).expect(&msg).borrow_mut();
let module = &modules.get(&pkgpath).expect(&msg).borrow_mut().inner;
module.add_global(tpe, Some(AddressSpace::default()), name)
} else {
self.module
Expand Down Expand Up @@ -1248,6 +1270,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
backtrack_meta: RefCell::new(None),
import_names,
no_link,
debug: false,
modules: RefCell::new(HashMap::new()),
workdir,
}
Expand All @@ -1266,38 +1289,41 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
let has_main_pkg = self.program.pkgs.contains_key(MAIN_PKG_PATH);
let function = if self.no_link {
let mut modules = self.modules.borrow_mut();
let name = if has_main_pkg {
MAIN_PKG_PATH.to_string()
// Pkgpath
let (pkgpath, function_name) = if has_main_pkg {
(MAIN_PKG_PATH.to_string(), MODULE_NAME.to_string())
} else {
assert!(self.program.pkgs.len() == 1);
format!(
let pkgpath = format!(
"{}{}",
kclvm_runtime::PKG_PATH_PREFIX,
self.program
.pkgs
.keys()
.next()
.expect(kcl_error::INTERNAL_ERROR_MSG)
);
(
pkgpath.clone(),
format!(
"${}.{}",
pkgpath_without_prefix!(pkgpath),
PKG_INIT_FUNCTION_SUFFIX
),
)
};
let module = self.context.create_module(name.as_str());
let function_name = if has_main_pkg {
MODULE_NAME.to_string()
} else {
format!(
"${}.{}",
pkgpath_without_prefix!(name),
PKG_INIT_FUNCTION_SUFFIX
)
};
let module = self.context.create_module(pkgpath.as_str());
let function = module.add_function(
// Function name
function_name.as_str(),
// Function type
if has_main_pkg { fn_type } else { void_fn_type },
None,
);
modules.insert(name.to_string(), RefCell::new(module));
modules.insert(
pkgpath.to_string(),
RefCell::new(self.create_debug_module(module)),
);
function
} else {
self.module.add_function(
Expand Down Expand Up @@ -1398,7 +1424,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
};
let path = std::path::Path::new(&path);
// Build LLVM module to a `.o` object file.
self.build_object_file(&module.borrow(), path)?;
self.build_object_file(&module.borrow().inner, path)?;
}
} else {
// Build LLVM module to a `.o` object file.
Expand All @@ -1408,51 +1434,6 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
Ok(())
}

/// Compile AST Modules, which requires traversing three times.
/// 1. scan all possible global variables and allocate undefined values to global pointers.
/// 2. build all user-defined schema/rule types.
/// 3. generate all LLVM IR codes for the third time.
fn compile_ast_modules(&self, modules: &'ctx [ast::Module]) {
// Scan global variables
for ast_module in modules {
{
self.filename_stack
.borrow_mut()
.push(ast_module.filename.clone());
}
// Pre define global variables with undefined values
self.predefine_global_vars(ast_module);
{
self.filename_stack.borrow_mut().pop();
}
}
// Scan global types
for ast_module in modules {
{
self.filename_stack
.borrow_mut()
.push(ast_module.filename.clone());
}
self.compile_module_import_and_types(ast_module);
{
self.filename_stack.borrow_mut().pop();
}
}
// Compile the ast module in the pkgpath.
for ast_module in modules {
{
self.filename_stack
.borrow_mut()
.push(ast_module.filename.clone());
}
self.walk_module(ast_module)
.expect(kcl_error::COMPILE_ERROR_MSG);
{
self.filename_stack.borrow_mut().pop();
}
}
}

/// Build LLVM module to a `.o` object file.
///
/// TODO: WASM and cross platform build.
Expand Down Expand Up @@ -1569,7 +1550,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
let pkgpath = self.current_pkgpath();
let msg = format!("pkgpath {} is not found", pkgpath);
let modules = self.modules.borrow_mut();
let module = modules.get(&pkgpath).expect(&msg).borrow_mut();
let module = &modules.get(&pkgpath).expect(&msg).borrow_mut().inner;
module.add_global(tpe, Some(AddressSpace::default()), name)
} else {
self.module
Expand Down Expand Up @@ -2019,7 +2000,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
let current_pkgpath = self.current_pkgpath();
let modules = self.modules.borrow();
let msg = format!("pkgpath {} is not found", current_pkgpath);
let module = modules.get(&current_pkgpath).expect(&msg).borrow();
let module = &modules.get(&current_pkgpath).expect(&msg).borrow().inner;
let tpe = self.value_ptr_type();
let mut global_var_maps = self.global_vars.borrow_mut();
let pkgpath = self.current_pkgpath();
Expand Down Expand Up @@ -2100,6 +2081,55 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
var_map
}

/// Load value from name.
pub fn load_value(&self, pkgpath: &str, names: &[&str]) -> CompileResult<'ctx> {
if names.is_empty() {
return Err(kcl_error::KCLError {
message: "error: read value from empty name".to_string(),
ty: kcl_error::KCLErrorType::Compile,
});
}
let name = names[0];
let get = |name: &str| {
// Get from schema
if self.is_in_schema() && !self.is_in_lambda() && !self.is_local_var(name) {
self.get_variable_in_schema(name)
} else {
// Get from local scope including lambda arguments, lambda variables,
// loop variables or global variables.
self.get_variable(name)
}
};
if names.len() == 1 {
get(name)
} else {
let mut value = if pkgpath.is_empty() {
get(name)
} else {
self.ok_result()
}
.expect(kcl_error::INTERNAL_ERROR_MSG);
for i in 0..names.len() - 1 {
let attr = names[i + 1];
if i == 0 && !pkgpath.is_empty() {
value = if self.no_link {
self.get_external_variable_in_pkgpath(attr, pkgpath)
} else {
self.get_variable_in_pkgpath(attr, pkgpath)
}
.expect(kcl_error::INTERNAL_ERROR_MSG)
} else {
let attr = self.native_global_string(attr, "").into();
value = self.build_call(
&ApiFunc::kclvm_value_load_attr.name(),
&[self.current_runtime_ctx_ptr(), value, attr],
);
}
}
Ok(value)
}
}

/// Push a lambda definition scope into the lambda stack
#[inline]
pub fn push_lambda(&self, scope: usize) {
Expand Down Expand Up @@ -2131,6 +2161,16 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
.expect(kcl_error::INTERNAL_ERROR_MSG)
}

#[inline]
pub fn is_in_schema(&self) -> bool {
self.schema_stack.borrow().len() > 0
}

#[inline]
pub fn is_local_var(&self, name: &str) -> bool {
self.local_vars.borrow().contains(name)
}

/// Push a function call frame into the function stack
#[inline]
pub fn push_function(&self, function: FunctionValue<'ctx>) {
Expand Down
2 changes: 1 addition & 1 deletion kclvm/compiler/src/codegen/llvm/emit.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 The KCL Authors. All rights reserved.
// Copyright The KCL Authors. All rights reserved.

use indexmap::IndexMap;
use inkwell::module::Module;
Expand Down
Loading

0 comments on commit 9d7d3d2

Please sign in to comment.