Skip to content

Commit 72616b5

Browse files
authored
Add initializers to the global constructors (#1327)
* Use global ctors to initialize the project Added a ProjectInit pou type to make it easy to find the initializers * Update snapshot tests * Update lit tests
1 parent bb5fe4b commit 72616b5

File tree

389 files changed

+909
-314
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

389 files changed

+909
-314
lines changed

Cargo.lock

Lines changed: 236 additions & 230 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/plc_ast/src/ast.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ pub enum PouType {
258258
Class,
259259
Method { owner_class: String },
260260
Init,
261+
ProjectInit,
261262
}
262263

263264
impl Display for PouType {
@@ -270,6 +271,7 @@ impl Display for PouType {
270271
PouType::Class => write!(f, "Class"),
271272
PouType::Method { .. } => write!(f, "Method"),
272273
PouType::Init => write!(f, "Init"),
274+
PouType::ProjectInit => write!(f, "ProjectInit"),
273275
}
274276
}
275277
}
@@ -283,6 +285,10 @@ impl PouType {
283285
None
284286
}
285287
}
288+
289+
pub fn is_function_or_init(&self) -> bool {
290+
matches!(self, PouType::Function | PouType::Init | PouType::ProjectInit)
291+
}
286292
}
287293

288294
#[derive(Debug, PartialEq)]

compiler/plc_driver/src/tests/snapshots/plc_driver__tests__external_files__external_file_function_call.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ declare i16 @external()
2424
; ModuleID = '__init___TestProject'
2525
source_filename = "__init___TestProject"
2626

27+
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @__init___TestProject, i8* null }]
28+
2729
define void @__init___TestProject() {
2830
entry:
2931
ret void

compiler/plc_driver/src/tests/snapshots/plc_driver__tests__external_files__external_file_global_var.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ declare i16 @external()
3232
; ModuleID = '__init___TestProject'
3333
source_filename = "__init___TestProject"
3434

35+
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @__init___TestProject, i8* null }]
36+
3537
define void @__init___TestProject() {
3638
entry:
3739
ret void

compiler/plc_driver/src/tests/snapshots/plc_driver__tests__multi_files__multiple_files_in_different_locations_with_debug_info.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ source_filename = "__init___TestProject"
137137
%mainProg = type {}
138138

139139
@mainProg_instance = external global %mainProg, !dbg !0
140+
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @__init___TestProject, i8* null }]
140141

141142
define void @__init___TestProject() !dbg !10 {
142143
entry:

compiler/plc_driver/src/tests/snapshots/plc_driver__tests__multi_files__multiple_files_with_debug_info.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ source_filename = "__init___TestProject"
137137
%mainProg = type {}
138138

139139
@mainProg_instance = external global %mainProg, !dbg !0
140+
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @__init___TestProject, i8* null }]
140141

141142
define void @__init___TestProject() !dbg !10 {
142143
entry:

compiler/plc_driver/src/tests/snapshots/plc_driver__tests__multi_files__multiple_source_files_generated.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ source_filename = "__init___TestProject"
5454
%mainProg = type {}
5555

5656
@mainProg_instance = external global %mainProg
57+
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @__init___TestProject, i8* null }]
5758

5859
define void @__init___TestProject() {
5960
entry:

src/codegen/debug.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ impl<'ink> DebugBuilder<'ink> {
531531
}
532532
}
533533
let implementation = pou.find_implementation(index).expect("A POU will have an impl at this stage");
534-
if implementation.implementation_type != ImplementationType::Function {
534+
if !implementation.get_implementation_type().is_function_or_init() {
535535
if implementation.get_implementation_type() == &ImplementationType::Method {
536536
//Methods ignored for now
537537
} else {

src/codegen/generators/pou_generator.rs

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use crate::index::Index;
3030
use index::VariableType;
3131

3232
use inkwell::{
33-
module::Module,
33+
module::{Linkage, Module},
3434
types::{BasicMetadataTypeEnum, BasicTypeEnum, FunctionType},
3535
values::{BasicValue, BasicValueEnum, FunctionValue},
3636
AddressSpace,
@@ -113,7 +113,7 @@ pub fn generate_global_constants_for_pou_members<'ink>(
113113
});
114114
for implementation in implementations {
115115
let type_name = implementation.get_type_name();
116-
if index.is_init_function(type_name) {
116+
if implementation.is_init() {
117117
// initializer functions don't need global constants to initialize members
118118
continue;
119119
}
@@ -235,10 +235,7 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> {
235235
}
236236
_ => {
237237
dti.map(|it| {
238-
if !matches!(
239-
implementation.get_implementation_type(),
240-
ImplementationType::Function
241-
) {
238+
if !implementation.get_implementation_type().is_function_or_init() {
242239
return *p;
243240
}
244241
// for aggregate function parameters we will generate a pointer instead of the value type.
@@ -296,9 +293,11 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> {
296293

297294
let curr_f = module.add_function(implementation.get_call_name(), function_declaration, None);
298295

299-
if self.online_change.is_enabled() {
300-
let section_name = self.mangle_function(implementation)?;
301-
curr_f.set_section(Some(&section_name));
296+
let section_name = self.get_section(implementation)?;
297+
curr_f.set_section(section_name.as_deref());
298+
299+
if implementation.get_implementation_type().is_project_init() {
300+
self.add_global_constructor(module, curr_f)?;
302301
}
303302

304303
let pou_name = implementation.get_call_name();
@@ -320,14 +319,52 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> {
320319
Ok(curr_f)
321320
}
322321

322+
/// Generates a global constructors entry
323+
/// The entry contains the a call to the initializer function
324+
fn add_global_constructor(
325+
&self,
326+
module: &Module<'ink>,
327+
curr_f: FunctionValue<'ink>,
328+
) -> Result<(), Diagnostic> {
329+
//Create a constructor struct
330+
let ctor_str = self.llvm.context.struct_type(
331+
&[
332+
//Priority
333+
self.llvm.context.i32_type().as_basic_type_enum(),
334+
// Function pointer
335+
curr_f.as_global_value().as_basic_value_enum().get_type(),
336+
//Data
337+
self.llvm.context.i8_type().ptr_type(AddressSpace::default()).as_basic_type_enum(),
338+
],
339+
false,
340+
);
341+
342+
//Create an entry for the global constructor of the project
343+
let str_value = ctor_str.const_named_struct(&[
344+
self.llvm.context.i32_type().const_zero().as_basic_value_enum(),
345+
curr_f.as_global_value().as_basic_value_enum(),
346+
self.llvm.context.i8_type().ptr_type(AddressSpace::default()).const_zero().as_basic_value_enum(),
347+
]);
348+
//Create an array with the global constructor as an entry
349+
let arr = ctor_str.const_array(&[str_value]);
350+
//Create the global constructors variable or fetch it and append to it if already
351+
//availabe
352+
let global_ctors = module.get_global("llvm.global_ctors").unwrap_or_else(|| {
353+
module.add_global(arr.get_type().as_basic_type_enum(), None, "llvm.global_ctors")
354+
});
355+
356+
global_ctors.set_initializer(&arr);
357+
global_ctors.set_linkage(Linkage::Appending);
358+
Ok(())
359+
}
323360
/// creates and returns all parameters for the given implementation
324361
/// for functions, this method creates a full list of parameters, for other POUs
325362
/// this method creates a single state-struct parameter
326363
fn collect_parameters_for_implementation(
327364
&self,
328365
implementation: &ImplementationIndexEntry,
329366
) -> Result<Vec<BasicMetadataTypeEnum<'ink>>, Diagnostic> {
330-
if implementation.implementation_type != ImplementationType::Function {
367+
if !implementation.implementation_type.is_function_or_init() {
331368
let mut parameters = vec![];
332369
if implementation.get_implementation_type() == &ImplementationType::Method {
333370
let class_name =
@@ -426,7 +463,7 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> {
426463
}
427464

428465
// generate local variables
429-
if matches!(implementation.pou_type, PouType::Function | PouType::Init) {
466+
if implementation.pou_type.is_function_or_init() {
430467
self.generate_local_function_arguments_accessors(
431468
&mut local_index,
432469
&implementation.type_name,
@@ -877,4 +914,12 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> {
877914
None
878915
}
879916
}
917+
918+
fn get_section(&self, implementation: &ImplementationIndexEntry) -> Result<Option<String>, Diagnostic> {
919+
if self.online_change.is_enabled() {
920+
self.mangle_function(implementation).map(Some)
921+
} else {
922+
Ok(None)
923+
}
924+
}
880925
}

src/codegen/generators/statement_generator.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,7 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> {
280280
if self.annotations.get(left_statement).is_some_and(|it| {
281281
// TODO(mhasel): ideally the resolver decides which assignment statement to call when lowering the init functions,
282282
// but that requires refactoring of how `aliases` and `reference to` LHS/RHS nodes are annotated. this is a workaround.
283-
self.index.is_init_function(self.function_context.linking_context.get_call_name())
284-
&& (it.is_alias() || it.is_reference_to())
283+
self.function_context.linking_context.is_init() && (it.is_alias() || it.is_reference_to())
285284
}) {
286285
return self.generate_ref_assignment(left_statement, right_statement);
287286
};

0 commit comments

Comments
 (0)