Skip to content

Commit 89b1822

Browse files
committed
rusty: Work around race conditions when compiling multiple modules
This commit also adds workarounds to make the integration of the generated code with our online change runtime work well. wip: almost done with Mutex hashmap NOTE: Reuse got_indices member from LlvmIndex instead wip: it works? src/test_utils: wip: Make these function compile after latest changes section_mangler: Fix emitted format wip codegen custom GOT as a non-external array wip: running onlinechangexmpl almost works! crashes on signal1() more hacks cleanup cleanup
1 parent acdf708 commit 89b1822

File tree

12 files changed

+289
-121
lines changed

12 files changed

+289
-121
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/plc_driver/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ plc_index = { path = "../plc_index" }
1616

1717
serde = { version = "1.0", features = ["derive"] }
1818
serde_json = "1"
19+
toml = "0.5"
1920
clap = { version = "3.0", features = ["derive"] }
2021
rayon = "1.6.1"
2122
tempfile = "3"

compiler/plc_driver/src/cli.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,9 @@ pub fn get_config_format(name: &str) -> Option<ConfigFormat> {
328328

329329
impl CompileParameters {
330330
pub fn parse<T: AsRef<OsStr> + AsRef<str>>(args: &[T]) -> Result<CompileParameters, ParameterError> {
331-
CompileParameters::try_parse_from(args).and_then(|result| {
331+
CompileParameters::try_parse_from(args).and_then(|mut result| {
332+
result.got_layout_file = Some(String::from("tmp.json"));
333+
332334
if result.sysroot.len() > result.target.len() {
333335
let mut cmd = CompileParameters::command();
334336
Err(cmd.error(

compiler/plc_driver/src/pipelines.rs

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use std::{
2+
collections::HashMap,
23
env,
34
fs::{self, File},
45
io::Write,
56
path::{Path, PathBuf},
7+
sync::Mutex,
68
};
79

810
use crate::{CompileOptions, LinkOptions};
@@ -33,6 +35,42 @@ use project::{
3335
use rayon::prelude::*;
3436
use source_code::{source_location::SourceLocation, SourceContainer};
3537

38+
use serde_json;
39+
use toml;
40+
41+
pub fn read_got_layout(location: &str, format: ConfigFormat) -> Result<HashMap<String, u64>, Diagnostic> {
42+
if !Path::new(location).is_file() {
43+
// Assume if the file doesn't exist that there is no existing GOT layout yet. write_got_layout will handle
44+
// creating our file when we want to.
45+
return Ok(HashMap::new());
46+
}
47+
48+
let s = fs::read_to_string(location)
49+
.map_err(|_| Diagnostic::new("GOT layout could not be read from file"))?;
50+
match format {
51+
ConfigFormat::JSON => serde_json::from_str(&s)
52+
.map_err(|_| Diagnostic::new("Could not deserialize GOT layout from JSON")),
53+
ConfigFormat::TOML => {
54+
toml::de::from_str(&s).map_err(|_| Diagnostic::new("Could not deserialize GOT layout from TOML"))
55+
}
56+
}
57+
}
58+
59+
fn write_got_layout(
60+
got_entries: HashMap<String, u64>,
61+
location: &str,
62+
format: ConfigFormat,
63+
) -> Result<(), Diagnostic> {
64+
let s = match format {
65+
ConfigFormat::JSON => serde_json::to_string(&got_entries)
66+
.map_err(|_| Diagnostic::new("Could not serialize GOT layout to JSON"))?,
67+
ConfigFormat::TOML => toml::ser::to_string(&got_entries)
68+
.map_err(|_| Diagnostic::new("Could not serialize GOT layout to TOML"))?,
69+
};
70+
71+
fs::write(location, s).map_err(|_| Diagnostic::new("GOT layout could not be written to file"))
72+
}
73+
3674
///Represents a parsed project
3775
///For this struct to be built, the project would have been parsed correctly and an AST would have
3876
///been generated
@@ -234,8 +272,15 @@ impl<T: SourceContainer + Sync> AnnotatedProject<T> {
234272
.iter()
235273
.map(|(unit, dependencies, literals)| {
236274
let context = CodegenContext::create();
237-
self.generate_module(&context, compile_options, unit, dependencies, literals)
238-
.map(|it| it.persist_to_string())
275+
self.generate_module(
276+
&context,
277+
compile_options,
278+
unit,
279+
dependencies,
280+
literals,
281+
todo!("GOT layout for codegen_to_string?"),
282+
)
283+
.map(|it| it.persist_to_string())
239284
})
240285
.collect()
241286
}
@@ -249,7 +294,14 @@ impl<T: SourceContainer + Sync> AnnotatedProject<T> {
249294
.units
250295
.iter()
251296
.map(|(unit, dependencies, literals)| {
252-
self.generate_module(context, compile_options, unit, dependencies, literals)
297+
self.generate_module(
298+
context,
299+
compile_options,
300+
unit,
301+
dependencies,
302+
literals,
303+
todo!("give GOT layout for single modules?"),
304+
)
253305
})
254306
.reduce(|a, b| {
255307
let a = a?;
@@ -269,6 +321,7 @@ impl<T: SourceContainer + Sync> AnnotatedProject<T> {
269321
unit: &CompilationUnit,
270322
dependencies: &FxIndexSet<Dependency>,
271323
literals: &StringLiterals,
324+
got_layout: &Mutex<Option<HashMap<String, u64>>>,
272325
) -> Result<GeneratedModule<'ctx>, Diagnostic> {
273326
let mut code_generator = plc::codegen::CodeGen::new(
274327
context,
@@ -286,8 +339,9 @@ impl<T: SourceContainer + Sync> AnnotatedProject<T> {
286339
literals,
287340
dependencies,
288341
&self.index,
342+
got_layout,
289343
)?;
290-
code_generator.generate(context, unit, &self.annotations, &self.index, &llvm_index)
344+
code_generator.generate(context, unit, &self.annotations, &self.index, llvm_index)
291345
}
292346

293347
pub fn codegen_single_module<'ctx>(
@@ -332,6 +386,15 @@ impl<T: SourceContainer + Sync> AnnotatedProject<T> {
332386
});
333387
ensure_compile_dirs(targets, &compile_directory)?;
334388
let targets = if targets.is_empty() { &[Target::System] } else { targets };
389+
390+
let got_layout = compile_options
391+
.got_layout_file
392+
.as_ref()
393+
.map(|path| read_got_layout(path, ConfigFormat::JSON))
394+
.transpose()?;
395+
396+
let got_layout = Mutex::new(got_layout);
397+
335398
let res = targets
336399
.par_iter()
337400
.map(|target| {
@@ -365,8 +428,15 @@ impl<T: SourceContainer + Sync> AnnotatedProject<T> {
365428
};
366429

367430
let context = CodegenContext::create(); //Create a build location for the generated object files
368-
let module =
369-
self.generate_module(&context, compile_options, unit, dependencies, literals)?;
431+
let module = self.generate_module(
432+
&context,
433+
compile_options,
434+
unit,
435+
dependencies,
436+
literals,
437+
&got_layout,
438+
)?;
439+
370440
module
371441
.persist(
372442
Some(&compile_directory),
@@ -385,6 +455,10 @@ impl<T: SourceContainer + Sync> AnnotatedProject<T> {
385455
})
386456
.collect::<Result<Vec<_>, Diagnostic>>()?;
387457

458+
compile_options.got_layout_file.as_ref().map(|path| {
459+
write_got_layout(got_layout.into_inner().unwrap().unwrap(), path, ConfigFormat::JSON)
460+
});
461+
388462
Ok(res)
389463
}
390464

compiler/section_mangler/src/lib.rs

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,27 @@ pub struct VariableMangler {
6868
ty: Type,
6969
}
7070

71+
pub const RUSTY_PREFIX: &str = "$RUSTY$";
72+
73+
// TODO: How to encode variadics?
74+
fn mangle_function(FunctionMangler { name, parameters, return_type }: FunctionMangler) -> String {
75+
/* FIXME: Is that correct? */
76+
let return_type = return_type.unwrap_or(Type::Void);
77+
78+
let mangled = match parameters.as_slice() {
79+
[] => format!("{return_type}[]"),
80+
parameters => {
81+
parameters.iter().fold(return_type.to_string(), |mangled, arg| format!("{mangled}[{arg}]"))
82+
}
83+
};
84+
85+
format!("{name}:{mangled}")
86+
}
87+
88+
fn mangle_variable(VariableMangler { name, ty }: VariableMangler) -> String {
89+
format!("{name}:{ty}")
90+
}
91+
7192
impl SectionMangler {
7293
pub fn function<S: Into<String>>(name: S) -> SectionMangler {
7394
SectionMangler::Function(FunctionMangler { name: name.into(), parameters: vec![], return_type: None })
@@ -111,7 +132,7 @@ impl SectionMangler {
111132
SectionMangler::Variable(v) => ("var", mangle_variable(v)),
112133
};
113134

114-
format!("{prefix}-{content}")
135+
format!("{RUSTY_PREFIX}{prefix}-{content}")
115136
}
116137
}
117138

@@ -249,19 +270,3 @@ impl fmt::Display for Type {
249270
}
250271
}
251272
}
252-
253-
pub const PREFIX: &str = "$RUSTY$";
254-
255-
// TODO: How to encode variadics?
256-
fn mangle_function(FunctionMangler { name, parameters, return_type }: FunctionMangler) -> String {
257-
let mangled = parameters
258-
.into_iter()
259-
/* FIXME: Is that correct? */
260-
.fold(return_type.unwrap_or(Type::Void).to_string(), |mangled, arg| format!("{mangled}[{arg}]"));
261-
262-
format!("{PREFIX}{name}:{mangled}")
263-
}
264-
265-
fn mangle_variable(VariableMangler { name, ty }: VariableMangler) -> String {
266-
format!("{PREFIX}{name}:{ty}")
267-
}

compiler/section_mangler/src/parser.rs

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{FunctionArgument, SectionMangler, Type};
1+
use crate::{FunctionArgument, SectionMangler, StringEncoding, Type};
22

33
use std::str;
44

@@ -21,7 +21,7 @@ fn parse_prefix(input: &str) -> ParseResult<Prefix> {
2121
let fn_prefix = tag("fn").map(|_| Prefix::Fn);
2222
let var_prefix = tag("var").map(|_| Prefix::Var);
2323

24-
let (input, _) = tag(crate::PREFIX)(input)?;
24+
let (input, _) = tag(crate::RUSTY_PREFIX)(input)?;
2525
let (input, prefix) = alt((fn_prefix, var_prefix))(input)?;
2626

2727
Ok((input, prefix))
@@ -75,8 +75,29 @@ fn type_enum(input: &str) -> ParseResult<Type> {
7575
.parse(input)
7676
}
7777

78+
fn string_encoding(input: &str) -> ParseResult<StringEncoding> {
79+
let utf8 = tag("8u").map(|_| StringEncoding::Utf8);
80+
let utf16 = tag("16u").map(|_| StringEncoding::Utf16);
81+
82+
alt((utf8, utf16))(input)
83+
}
84+
85+
fn type_string(input: &str) -> ParseResult<Type> {
86+
char('s')
87+
.and(string_encoding)
88+
.and(number::<usize>)
89+
.map(|((_, encoding), size)| Type::String { size, encoding })
90+
.parse(input)
91+
}
92+
93+
fn type_array(input: &str) -> ParseResult<Type> {
94+
char('a').and(parse_type).map(|(_, inner_ty)| Type::Array { inner: Box::new(inner_ty) }).parse(input)
95+
}
96+
7897
fn parse_type(input: &str) -> ParseResult<Type> {
79-
alt((type_void, type_integer, type_float, type_pointer, type_struct, type_enum))(input)
98+
alt((type_void, type_integer, type_float, type_pointer, type_struct, type_enum, type_string, type_array))(
99+
input,
100+
)
80101
}
81102

82103
fn parse_var_content<'i>(input: &'i str, name: &str) -> ParseResult<'i, SectionMangler> {
@@ -188,6 +209,7 @@ mod tests {
188209
// this needs to be handled by the toplevel parse function
189210
assert!(type_struct("r0u8u8").is_ok());
190211
assert!(type_struct("r1u8u8").is_ok());
212+
assert!(type_struct("r5s8u1025s8u2049s8u3u64s8u3").is_ok());
191213

192214
// invalid number of elements
193215
assert!(type_struct("r15u8").is_err());
@@ -235,4 +257,67 @@ mod tests {
235257

236258
assert_eq!(mangled.name(), "Color.red");
237259
}
260+
261+
#[test]
262+
fn parse_complex1() {
263+
let mangled = SectionMangler::from("$RUSTY$var-__File__init:r5s8u1025s8u2049s8u3u64s8u3");
264+
265+
assert_eq!(mangled.name(), "__File__init");
266+
}
267+
268+
#[test]
269+
fn parse_complex2() {
270+
let inputs = [
271+
"$RUSTY$var-__CosineSignal__init:r4f64i32f64f64",
272+
"$RUSTY$var-__File__init:r5s8u1025s8u2049s8u3u64s8u3",
273+
"$RUSTY$var-__SineSignal__init:r4f64i32f64f64",
274+
"$RUSTY$var-__mainProg_state.Init:e3i32",
275+
"$RUSTY$var-__mainProg_state.Running:e3i32",
276+
"$RUSTY$var-__mainProg_state.Stopped:e3i32",
277+
"$RUSTY$var-__SR__init:r3u8u8u8",
278+
"$RUSTY$var-__RS__init:r3u8u8u8",
279+
"$RUSTY$var-__CTU__init:r6u8u8i16u8i16u8",
280+
"$RUSTY$var-__CTU_INT__init:r6u8u8i16u8i16u8",
281+
"$RUSTY$var-__CTU_DINT__init:r6u8u8i32u8i32u8",
282+
"$RUSTY$var-__CTU_UDINT__init:r6u8u8u32u8u32u8",
283+
"$RUSTY$var-__CTU_LINT__init:r6u8u8i64u8i64u8",
284+
"$RUSTY$var-__CTU_ULINT__init:r6u8u8u64u8u64u8",
285+
"$RUSTY$var-__CTD__init:r6u8u8i16u8i16u8",
286+
"$RUSTY$var-__CTD_INT__init:r6u8u8i16u8i16u8",
287+
"$RUSTY$var-__CTD_DINT__init:r6u8u8i32u8i32u8",
288+
"$RUSTY$var-__CTD_UDINT__init:r6u8u8u32u8u32u8",
289+
"$RUSTY$var-__CTD_LINT__init:r6u8u8i64u8i64u8",
290+
"$RUSTY$var-__CTD_ULINT__init:r6u8u8u64u8u64u8",
291+
"$RUSTY$var-__CTUD__init:r10u8u8u8u8i16u8u8i16u8u8",
292+
"$RUSTY$var-__CTUD_INT__init:r10u8u8u8u8i16u8u8i16u8u8",
293+
"$RUSTY$var-__CTUD_DINT__init:r10u8u8u8u8i32u8u8i32u8u8",
294+
"$RUSTY$var-__CTUD_UDINT__init:r10u8u8u8u8u32u8u8u32u8u8",
295+
"$RUSTY$var-__CTUD_LINT__init:r10u8u8u8u8i64u8u8i64u8u8",
296+
"$RUSTY$var-__CTUD_ULINT__init:r10u8u8u8u8u64u8u8u64u8u8",
297+
"$RUSTY$var-__R_TRIG__init:r3u8u8u8",
298+
"$RUSTY$var-__F_TRIG__init:r3u8u8u8",
299+
"$RUSTY$var-__TP__init:r7u8i64u8i64u8u8au8",
300+
"$RUSTY$var-__TP_TIME__init:r7u8i64u8i64u8u8au8",
301+
"$RUSTY$var-__TP_LTIME__init:r7u8i64u8i64u8u8au8",
302+
"$RUSTY$var-__TON__init:r7u8i64u8i64u8u8au8",
303+
"$RUSTY$var-__TON_TIME__init:r7u8i64u8i64u8u8au8",
304+
"$RUSTY$var-__TON_LTIME__init:r7u8i64u8i64u8u8au8",
305+
"$RUSTY$var-__TOF__init:r7u8i64u8i64u8u8au8",
306+
"$RUSTY$var-__TOF_TIME__init:r7u8i64u8i64u8u8au8",
307+
"$RUSTY$var-__TOF_LTIME__init:r7u8i64u8i64u8u8au8",
308+
"$RUSTY$fn-CosineSignal:v[f64][i32][f64]",
309+
"$RUSTY$fn-File:v[s8u1025][s8u2049][s8u3]",
310+
"$RUSTY$fn-File.Open:v",
311+
"$RUSTY$fn-File.Write:v",
312+
"$RUSTY$fn-File.Close:v",
313+
"$RUSTY$fn-File.Clear:v",
314+
"$RUSTY$fn-SineSignal:v[f64][i32][f64]",
315+
"$RUSTY$fn-mainProg:v",
316+
"$RUSTY$var-mainProg:r7i32r4f64i32f64f64r4f64i32f64f64e3i32r5s8u1025s8u2049s8u3u64s8u3r5s8u1025s8u2049s8u3u64s8u3r5s8u1025s8u2049s8u3u64s8u3"
317+
];
318+
319+
inputs.into_iter().for_each(|input| {
320+
let _ = SectionMangler::from(dbg!(input));
321+
});
322+
}
238323
}

0 commit comments

Comments
 (0)