Skip to content

Commit

Permalink
first bit of lifting the GOT layout out of generate_llvm_index.
Browse files Browse the repository at this point in the history
This bit takes care of passing the parameters properly and adding the required
fields to the required structs. there is also the lifting of the "reading" of GOT layouts to the function calling `generate_module`.
now we need to extract the generated new GOT layouts from the generated modules (?) and merge them together OR, which would be preferable,
pass a mutex to the GotLayout with abstractions for adding a new index in it.

NOTE: How to do that merge afterwards? How to access that mutex properly?
NOTE: If we return a GeneratedModule and then collect those into a vector of GeneratedModule, we need to merge the GotLayouts at this point
NOTE: ...which is why it probably makes more sense to go with the mutex, this way there is no got layout to return in GeneratedModule?
  • Loading branch information
CohenArthur committed Jun 20, 2024
1 parent e80995a commit 6ec6d7f
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 100 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions compiler/plc_driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ plc_index = { path = "../plc_index" }

serde = { version = "1.0", features = ["derive"] }
serde_json = "1"
toml = "0.5"
clap = { version = "3.0", features = ["derive"] }
rayon = "1.6.1"
tempfile = "3"
Expand Down
4 changes: 3 additions & 1 deletion compiler/plc_driver/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,9 @@ pub fn get_config_format(name: &str) -> Option<ConfigFormat> {

impl CompileParameters {
pub fn parse<T: AsRef<OsStr> + AsRef<str>>(args: &[T]) -> Result<CompileParameters, ParameterError> {
CompileParameters::try_parse_from(args).and_then(|result| {
CompileParameters::try_parse_from(args).and_then(|mut result| {
result.got_layout_file = Some(String::from("tmp.json"));

if result.sysroot.len() > result.target.len() {
let mut cmd = CompileParameters::command();
Err(cmd.error(
Expand Down
78 changes: 72 additions & 6 deletions compiler/plc_driver/src/pipelines.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::{
collections::HashMap,
env,
fs::{self, File},
io::Write,
Expand Down Expand Up @@ -33,6 +34,42 @@ use project::{
use rayon::prelude::*;
use source_code::{source_location::SourceLocation, SourceContainer};

use serde_json;
use toml;

pub fn read_got_layout(location: &str, format: ConfigFormat) -> Result<HashMap<String, u64>, Diagnostic> {
if !Path::new(location).is_file() {
// Assume if the file doesn't exist that there is no existing GOT layout yet. write_got_layout will handle
// creating our file when we want to.
return Ok(HashMap::new());
}

let s = fs::read_to_string(location)
.map_err(|_| Diagnostic::new("GOT layout could not be read from file"))?;
match format {
ConfigFormat::JSON => serde_json::from_str(&s)
.map_err(|_| Diagnostic::new("Could not deserialize GOT layout from JSON")),
ConfigFormat::TOML => {
toml::de::from_str(&s).map_err(|_| Diagnostic::new("Could not deserialize GOT layout from TOML"))
}
}
}

fn write_got_layout(
got_entries: HashMap<String, u64>,
location: &str,
format: ConfigFormat,
) -> Result<(), Diagnostic> {
let s = match format {
ConfigFormat::JSON => serde_json::to_string(&got_entries)
.map_err(|_| Diagnostic::new("Could not serialize GOT layout to JSON"))?,
ConfigFormat::TOML => toml::ser::to_string(&got_entries)
.map_err(|_| Diagnostic::new("Could not serialize GOT layout to TOML"))?,
};

fs::write(location, s).map_err(|_| Diagnostic::new("GOT layout could not be written to file"))
}

///Represents a parsed project
///For this struct to be built, the project would have been parsed correctly and an AST would have
///been generated
Expand Down Expand Up @@ -234,8 +271,15 @@ impl<T: SourceContainer + Sync> AnnotatedProject<T> {
.iter()
.map(|(unit, dependencies, literals)| {
let context = CodegenContext::create();
self.generate_module(&context, compile_options, unit, dependencies, literals)
.map(|it| it.persist_to_string())
self.generate_module(
&context,
compile_options,
unit,
dependencies,
literals,
todo!("GOT layout for codegen_to_string?"),
)
.map(|it| it.persist_to_string())
})
.collect()
}
Expand All @@ -249,7 +293,14 @@ impl<T: SourceContainer + Sync> AnnotatedProject<T> {
.units
.iter()
.map(|(unit, dependencies, literals)| {
self.generate_module(context, compile_options, unit, dependencies, literals)
self.generate_module(
context,
compile_options,
unit,
dependencies,
literals,
todo!("give GOT layout for singlemodules?"),
)
})
.reduce(|a, b| {
let a = a?;
Expand All @@ -269,6 +320,7 @@ impl<T: SourceContainer + Sync> AnnotatedProject<T> {
unit: &CompilationUnit,
dependencies: &FxIndexSet<Dependency>,
literals: &StringLiterals,
got_layout: Option<&HashMap<String, u64>>,
) -> Result<GeneratedModule<'ctx>, Diagnostic> {
let mut code_generator = plc::codegen::CodeGen::new(
context,
Expand All @@ -286,8 +338,9 @@ impl<T: SourceContainer + Sync> AnnotatedProject<T> {
literals,
dependencies,
&self.index,
got_layout,
)?;
code_generator.generate(context, unit, &self.annotations, &self.index, &llvm_index)
code_generator.generate(context, unit, &self.annotations, &self.index, llvm_index)
}

pub fn codegen_single_module<'ctx>(
Expand Down Expand Up @@ -332,6 +385,13 @@ impl<T: SourceContainer + Sync> AnnotatedProject<T> {
});
ensure_compile_dirs(targets, &compile_directory)?;
let targets = if targets.is_empty() { &[Target::System] } else { targets };

let got_layout = compile_options
.got_layout_file
.as_ref()
.map(|path| read_got_layout(&path, ConfigFormat::JSON))
.transpose()?;

let res = targets
.par_iter()
.map(|target| {
Expand Down Expand Up @@ -365,8 +425,14 @@ impl<T: SourceContainer + Sync> AnnotatedProject<T> {
};

let context = CodegenContext::create(); //Create a build location for the generated object files
let module =
self.generate_module(&context, compile_options, unit, dependencies, literals)?;
let module = self.generate_module(
&context,
compile_options,
unit,
dependencies,
literals,
got_layout.as_ref(),
)?;
module
.persist(
Some(&compile_directory),
Expand Down
91 changes: 30 additions & 61 deletions src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,46 +81,13 @@ pub struct CodeGen<'ink> {

pub struct GeneratedModule<'ink> {
module: Module<'ink>,
got_layout: Option<HashMap<String, u64>>,
engine: RefCell<Option<ExecutionEngine<'ink>>>,
}

type MainFunction<T, U> = unsafe extern "C" fn(*mut T) -> U;
type MainEmptyFunction<U> = unsafe extern "C" fn() -> U;

pub fn read_got_layout(location: &str, format: ConfigFormat) -> Result<HashMap<String, u64>, Diagnostic> {
if !Path::new(location).is_file() {
// Assume if the file doesn't exist that there is no existing GOT layout yet. write_got_layout will handle
// creating our file when we want to.
return Ok(HashMap::new());
}

let s =
fs::read_to_string(location).map_err(|_| Diagnostic::new("GOT layout could not be read from file"))?;
match format {
ConfigFormat::JSON => serde_json::from_str(&s)
.map_err(|_| Diagnostic::new("Could not deserialize GOT layout from JSON")),
ConfigFormat::TOML => {
toml::de::from_str(&s).map_err(|_| Diagnostic::new("Could not deserialize GOT layout from TOML"))
}
}
}

pub fn write_got_layout(
got_entries: HashMap<String, u64>,
location: &str,
format: ConfigFormat,
) -> Result<(), Diagnostic> {
let s = match format {
ConfigFormat::JSON => serde_json::to_string(&got_entries)
.map_err(|_| Diagnostic::new("Could not serialize GOT layout to JSON"))?,
ConfigFormat::TOML => toml::ser::to_string(&got_entries)
.map_err(|_| Diagnostic::new("Could not serialize GOT layout to TOML"))?,
};

fs::write(location, s).map_err(|_| Diagnostic::new("GOT layout could not be written to file"))?;
Ok(())
}

impl<'ink> CodeGen<'ink> {
/// constructs a new code-generator that generates CompilationUnits into a module with the given module_name
pub fn new(
Expand All @@ -144,6 +111,7 @@ impl<'ink> CodeGen<'ink> {
literals: &StringLiterals,
dependencies: &FxIndexSet<Dependency>,
global_index: &Index,
got_layout: Option<&HashMap<String, u64>>,
) -> Result<LlvmTypedIndex<'ink>, Diagnostic> {
let llvm = Llvm::new(context, context.create_builder());
let mut index = LlvmTypedIndex::default();
Expand All @@ -157,14 +125,8 @@ impl<'ink> CodeGen<'ink> {
)?;
index.merge(llvm_type_index);

let mut variable_generator = VariableGenerator::new(
&self.module,
&llvm,
global_index,
annotations,
&index,
&mut self.debug,
);
let mut variable_generator =
VariableGenerator::new(&self.module, &llvm, global_index, annotations, &index, &mut self.debug);

//Generate global variables
let llvm_gv_index =
Expand All @@ -173,30 +135,32 @@ impl<'ink> CodeGen<'ink> {

// Build our GOT layout here. We need to find all the names for globals, programs, and
// functions and assign them indices in the GOT, taking into account prior indices.
let program_globals = global_index
.get_program_instances()
.into_iter()
.fold(Vec::new(), |mut acc, p| {
let program_globals =
global_index.get_program_instances().into_iter().fold(Vec::new(), |mut acc, p| {
acc.push(p.get_name());
acc.push(p.get_qualified_name());
acc
});
let functions = global_index.get_pous().values()
.filter_map(|p| match p {
PouIndexEntry::Function { name, linkage: LinkageType::Internal, is_generated: false, .. }
| PouIndexEntry::FunctionBlock { name, linkage: LinkageType::Internal, .. } => Some(name.as_ref()),
_ => None,
});
let all_names = global_index
let functions = global_index.get_pous().values().filter_map(|p| match p {
PouIndexEntry::Function { name, linkage: LinkageType::Internal, is_generated: false, .. }
| PouIndexEntry::FunctionBlock { name, linkage: LinkageType::Internal, .. } => {
Some(name.as_ref())
}
_ => None,
});
let all_names = global_index
.get_globals()
.values()
.map(|g| g.get_qualified_name())
.chain(program_globals)
.chain(functions)
.map(|n| n.to_lowercase());

if let Some((location, format)) = &self.got_layout_file {
let got_entries = read_got_layout(location.as_str(), *format)?;
let all_names: Vec<_> = all_names.collect();
dbg!(all_names.len());

if let Some(got_entries) = got_layout {
// let got_entries = read_got_layout(location.as_str(), *format)?;
let mut new_symbols = Vec::new();
let mut new_got_entries = HashMap::new();
let mut new_got = HashMap::new();
Expand All @@ -222,8 +186,9 @@ impl<'ink> CodeGen<'ink> {
new_got.insert(idx, name.to_string());
}

// FIXME: Remove - moved out of there
// Now we can write new_got_entries back out to a file.
write_got_layout(new_got_entries, location.as_str(), *format)?;
// write_got_layout(new_got_entries, location.as_str(), *format)?;

// Construct our GOT as a new global array. We initialise this array in the loader code.
let got_size = new_got.keys().max().map_or(0, |m| *m + 1);
Expand Down Expand Up @@ -305,11 +270,11 @@ impl<'ink> CodeGen<'ink> {
unit: &CompilationUnit,
annotations: &AstAnnotations,
global_index: &Index,
llvm_index: &LlvmTypedIndex,
llvm_index: LlvmTypedIndex,
) -> Result<GeneratedModule<'ink>, Diagnostic> {
//generate all pous
let llvm = Llvm::new(context, context.create_builder());
let pou_generator = PouGenerator::new(llvm, global_index, annotations, llvm_index);
let pou_generator = PouGenerator::new(llvm, global_index, annotations, &llvm_index);

//Generate the POU stubs in the first go to make sure they can be referenced.
for implementation in &unit.implementations {
Expand All @@ -333,15 +298,19 @@ impl<'ink> CodeGen<'ink> {
}

#[cfg(not(feature = "verify"))]
Ok(GeneratedModule { module: self.module, engine: RefCell::new(None) })
Ok(GeneratedModule {
module: self.module,
got_layout: llvm_index.got_layout,
engine: RefCell::new(None),
})
}
}

impl<'ink> GeneratedModule<'ink> {
pub fn try_from_bitcode(context: &'ink CodegenContext, path: &Path) -> Result<Self, Diagnostic> {
let module = Module::parse_bitcode_from_path(path, context.deref())
.map_err(|it| Diagnostic::new(it.to_string_lossy()).with_error_code("E071"))?;
Ok(GeneratedModule { module, engine: RefCell::new(None) })
Ok(GeneratedModule { module, got_layout: None, engine: RefCell::new(None) })
}

pub fn try_from_ir(context: &'ink CodegenContext, path: &Path) -> Result<Self, Diagnostic> {
Expand All @@ -353,7 +322,7 @@ impl<'ink> GeneratedModule<'ink> {

log::debug!("{}", module.to_string());

Ok(GeneratedModule { module, engine: RefCell::new(None) })
Ok(GeneratedModule { module, got_layout: None, engine: RefCell::new(None) })
}

pub fn merge(self, other: GeneratedModule<'ink>) -> Result<Self, Diagnostic> {
Expand Down
Loading

0 comments on commit 6ec6d7f

Please sign in to comment.