Skip to content

Commit c8245a6

Browse files
committed
wip: add adrs, experimental skip externals not yet working as expected
1 parent 096fb5d commit c8245a6

File tree

5 files changed

+379
-15
lines changed

5 files changed

+379
-15
lines changed

compiler/plc_ast/src/ast.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,11 @@ impl VariableBlock {
517517
VariableBlock::default().with_block_type(VariableBlockType::Global)
518518
}
519519

520+
pub fn with_linkage(mut self, linkage: LinkageType) -> Self {
521+
self.linkage = linkage;
522+
self
523+
}
524+
520525
pub fn with_block_type(mut self, block_type: VariableBlockType) -> Self {
521526
self.kind = block_type;
522527
self

src/lowering/initializers.rs

Lines changed: 107 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,15 @@ impl InitVisitor {
127127

128128
fn create_var_config_init(statements: Vec<AstNode>, mut id_provider: IdProvider) -> CompilationUnit {
129129
let loc = SourceLocation::internal_in_unit(Some(INIT_COMPILATION_UNIT));
130-
let pou = new_pou(VAR_CONFIG_INIT, id_provider.next_id(), vec![], PouType::Init, &loc); // this can probably just be internal
131-
let implementation = new_implementation(VAR_CONFIG_INIT, statements, PouType::Init, loc);
130+
let pou = new_pou(VAR_CONFIG_INIT, id_provider.next_id(), vec![], PouType::Init, LinkageType::Internal, &loc); // this can probably just be internal
131+
let implementation = new_implementation(VAR_CONFIG_INIT, statements, PouType::Init, LinkageType::Internal, loc);
132132
new_unit(pou, implementation, INIT_COMPILATION_UNIT)
133133
}
134134

135135
fn create_init_units(lowerer: &InitVisitor) -> Vec<CompilationUnit> {
136136
let lookup = lowerer.unresolved_initializers.keys().map(|it| it.as_str()).collect::<FxIndexSet<_>>();
137137
lowerer
138-
.unresolved_initializers
138+
.unresolved_initializers
139139
.iter()
140140
.filter_map(|(container, init)| {
141141
// globals will be initialized in the `__init` body
@@ -158,11 +158,11 @@ fn create_init_unit(
158158
let mut id_provider = lowerer.ctxt.id_provider.clone();
159159
let init_fn_name = get_init_fn_name(container_name);
160160
log::trace!("creating {init_fn_name}");
161-
let (is_stateless, location) = lowerer
161+
let (is_stateless, location, linkage) = lowerer
162162
.index
163163
.find_pou(container_name)
164-
.map(|it| (it.is_function() || it.is_method(), it.get_location()))
165-
.unwrap_or_else(|| (false, &lowerer.index.get_type_or_panic(container_name).location));
164+
.map(|it| (it.is_function() || it.is_method(), it.get_location(), *it.get_linkage()))
165+
.unwrap_or_else(|| (false, &lowerer.index.get_type_or_panic(container_name).location, LinkageType::Internal));
166166

167167
if is_stateless {
168168
// functions do not get their own init-functions -
@@ -188,7 +188,7 @@ fn create_init_unit(
188188
"self".to_string(),
189189
);
190190

191-
let init_pou = new_pou(&init_fn_name, id_provider.next_id(), self_param, PouType::Init, &location);
191+
let init_pou = new_pou(&init_fn_name, id_provider.next_id(), self_param, PouType::Init, linkage, &location);
192192

193193
let mut statements = Vec::new();
194194

@@ -236,7 +236,7 @@ fn create_init_unit(
236236
.collect::<Vec<_>>();
237237

238238
let statements = [member_init_calls, statements].concat();
239-
let implementation = new_implementation(&init_fn_name, statements, PouType::Init, location);
239+
let implementation = new_implementation(&init_fn_name, statements, PouType::Init, linkage, location);
240240

241241
Some(new_unit(init_pou, implementation, INIT_COMPILATION_UNIT))
242242
}
@@ -261,8 +261,10 @@ fn create_user_init_units(lowerer: &InitVisitor) -> Vec<CompilationUnit> {
261261
location: location.clone(),
262262
}])];
263263

264+
265+
let linkage = lowerer.index.find_pou(container_name).map(|it|*it.get_linkage()).unwrap_or(LinkageType::Internal);
264266
let fn_name = get_user_init_fn_name(container_name);
265-
let init_pou = new_pou(&fn_name, id_provider.next_id(), param, PouType::Init, &location);
267+
let init_pou = new_pou(&fn_name, id_provider.next_id(), param, PouType::Init, linkage, &location);
266268

267269
let mut statements = lowerer
268270
.index
@@ -297,7 +299,7 @@ fn create_user_init_units(lowerer: &InitVisitor) -> Vec<CompilationUnit> {
297299
AstFactory::create_call_statement(op, None, id_provider.next_id(), location.clone());
298300
statements.push(call_statement);
299301
}
300-
let implementation = new_implementation(&fn_name, statements, PouType::Init, location);
302+
let implementation = new_implementation(&fn_name, statements, PouType::Init, linkage, location);
301303

302304
new_unit(init_pou, implementation, INIT_COMPILATION_UNIT)
303305
})
@@ -319,6 +321,7 @@ fn create_init_wrapper_function(
319321
id_provider.next_id(),
320322
vec![],
321323
PouType::ProjectInit,
324+
LinkageType::Internal,
322325
&SourceLocation::internal(),
323326
);
324327

@@ -387,7 +390,7 @@ fn create_init_wrapper_function(
387390
let user_init_calls = get_global_user_init_statements(lowerer);
388391
let statements = [calls, statements, user_init_calls].concat();
389392
let implementation =
390-
new_implementation(init_symbol_name, statements, PouType::ProjectInit, SourceLocation::internal());
393+
new_implementation(init_symbol_name, statements, PouType::ProjectInit, LinkageType::Internal, SourceLocation::internal());
391394
let mut global_init = new_unit(init_pou, implementation, init_symbol_name);
392395

393396
if skip_var_config {
@@ -449,6 +452,7 @@ fn new_pou(
449452
id: AstId,
450453
variable_blocks: Vec<VariableBlock>,
451454
kind: PouType,
455+
linkage: LinkageType,
452456
location: &SourceLocation,
453457
) -> Pou {
454458
Pou {
@@ -473,6 +477,7 @@ fn new_implementation(
473477
name: &str,
474478
statements: Vec<AstNode>,
475479
pou_type: PouType,
480+
linkage: LinkageType,
476481
location: SourceLocation,
477482
) -> Implementation {
478483
Implementation {
@@ -555,8 +560,13 @@ fn create_vtable_initializer(lowerer: &InitVisitor, ids: &mut IdProvider, pou_na
555560

556561
#[cfg(test)]
557562
mod tests {
563+
use inkwell::module::Linkage;
564+
use insta::assert_debug_snapshot;
565+
use plc_ast::ast::LinkageType;
558566
use test_utils::parse_and_validate_buffered_ast;
559567

568+
use crate::lowering::vtable;
569+
560570
#[test]
561571
fn usertype_todo_better_name_00() {
562572
let src = r#"
@@ -1638,4 +1648,90 @@ mod tests {
16381648
]
16391649
"#);
16401650
}
1651+
1652+
#[test]
1653+
fn function_block_initializer_with_base_call() {
1654+
let src = r#"
1655+
FUNCTION_BLOCK FB_Base
1656+
VAR
1657+
baseValue: DINT := 5;
1658+
END_VAR
1659+
END_FUNCTION_BLOCK
1660+
1661+
FUNCTION_BLOCK FB_Derived EXTENDS FB_Base
1662+
VAR
1663+
derivedValue: DINT := 10;
1664+
END_VAR
1665+
END_FUNCTION_BLOCK
1666+
"#;
1667+
1668+
let units = parse_and_validate_buffered_ast(src);
1669+
// Check that a base initializer call is generated
1670+
let init_unit = &units
1671+
.iter()
1672+
.find(|unit| unit.file.get_name().is_some_and(|name| name == "__initializers"))
1673+
.unwrap();
1674+
let init_base = init_unit.implementations.iter().find(|it| it.name == "__init_fb_base").unwrap();
1675+
assert_eq!(init_base.linkage, LinkageType::Internal);
1676+
// Check that a vtable_init for base was generated
1677+
let vtable_init_base = init_unit.implementations.iter().find(|it| it.name == "__init___vtable_fb_base").unwrap();
1678+
assert_eq!(vtable_init_base.linkage, LinkageType::Internal);
1679+
// Make sure the variable block containing the base vtable is internal
1680+
let variable_block = units[0].global_vars.iter().find(|it| it.variables.iter().any(|it| it.name == "__vtable_FB_Base_instance")).unwrap();
1681+
assert_eq!(variable_block.linkage, LinkageType::Internal);
1682+
// Make sure the derived initializer is still internal
1683+
let init_derived = init_unit.implementations.iter().find(|it| it.name == "__init_fb_derived").unwrap();
1684+
assert_eq!(init_derived.linkage, LinkageType::Internal);
1685+
// Make sure the derived vtable initializer is still internal
1686+
let vtable_init_derived = init_unit.implementations.iter().find(|it| it.name == "__init___vtable_fb_derived").unwrap();
1687+
assert_eq!(vtable_init_derived.linkage, LinkageType::Internal);
1688+
// Make sure the variable block containing the derived vtable is internal
1689+
let variable_block = units[0].global_vars.iter().find(|it| it.variables.iter().any(|it| it.name == "__vtable_FB_Derived_instance")).unwrap();
1690+
assert_eq!(variable_block.linkage, LinkageType::Internal);
1691+
}
1692+
1693+
1694+
#[test]
1695+
fn function_block_initializer_with_external_base_call() {
1696+
let src = r#"
1697+
{external}
1698+
FUNCTION_BLOCK FB_Base
1699+
VAR
1700+
baseValue: DINT := 5;
1701+
END_VAR
1702+
END_FUNCTION_BLOCK
1703+
1704+
FUNCTION_BLOCK FB_Derived EXTENDS FB_Base
1705+
VAR
1706+
derivedValue: DINT := 10;
1707+
END_VAR
1708+
END_FUNCTION_BLOCK
1709+
"#;
1710+
1711+
let units = parse_and_validate_buffered_ast(src);
1712+
// Check that a base initializer call is generated
1713+
let init_unit = &units
1714+
.iter()
1715+
.find(|unit| unit.file.get_name().is_some_and(|name| name == "__initializers"))
1716+
.unwrap();
1717+
let init_base = init_unit.implementations.iter().find(|it| it.name == "__init_fb_base").unwrap();
1718+
assert_eq!(init_base.linkage, LinkageType::External);
1719+
// Check that a vtable_init for base was generated
1720+
let vtable_init_base = init_unit.implementations.iter().find(|it| it.name == "__init___vtable_fb_base").unwrap();
1721+
assert_eq!(vtable_init_base.linkage, LinkageType::External);
1722+
// Make sure the variable block containing the base vtable is internal
1723+
let variable_block = units[0].global_vars.iter().find(|it| it.variables.iter().any(|it| it.name == "__vtable_FB_Base_instance")).unwrap();
1724+
assert_eq!(variable_block.linkage, LinkageType::External);
1725+
// Make sure the derived initializer is still internal
1726+
let init_derived = init_unit.implementations.iter().find(|it| it.name == "__init_fb_derived").unwrap();
1727+
assert_eq!(init_derived.linkage, LinkageType::Internal);
1728+
// Make sure the derived vtable initializer is still internal
1729+
let vtable_init_derived = init_unit.implementations.iter().find(|it| it.name == "__init___vtable_fb_derived").unwrap();
1730+
assert_eq!(vtable_init_derived.linkage, LinkageType::Internal);
1731+
// Make sure the variable block containing the derived vtable is internal
1732+
let variable_block = units[0].global_vars.iter().find(|it| it.variables.iter().any(|it| it.name == "__vtable_FB_Derived_instance")).unwrap();
1733+
assert_eq!(variable_block.linkage, LinkageType::Internal);
1734+
}
1735+
1736+
16411737
}

src/lowering/vtable.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,19 +89,31 @@ impl VirtualTableGenerator {
8989
pub fn generate(&mut self, index: &Index, units: &mut Vec<CompilationUnit>) {
9090
for unit in units {
9191
let mut definitions = Vec::new();
92-
let mut instances = Vec::new();
92+
let mut internal_instances = Vec::new();
93+
let mut external_instances = Vec::new();
9394

9495
for pou in unit.pous.iter_mut().filter(|pou| pou.kind.is_class() | pou.kind.is_function_block()) {
9596
self.patch_vtable_member(pou);
9697
let definition = self.generate_vtable_definition(index, pou);
9798
let instance = self.generate_vtable_instance(pou, &definition);
9899

99100
definitions.push(definition);
100-
instances.push(instance);
101+
if pou.linkage == LinkageType::External {
102+
external_instances.push(instance);
103+
} else {
104+
internal_instances.push(instance);
105+
}
101106
}
102107

103108
unit.user_types.extend(definitions);
104-
unit.global_vars.push(VariableBlock::global().with_variables(instances));
109+
unit.global_vars.push(VariableBlock::global().with_variables(internal_instances));
110+
if !external_instances.is_empty() {
111+
unit.global_vars.push(
112+
VariableBlock::global()
113+
.with_linkage(LinkageType::External)
114+
.with_variables(external_instances),
115+
);
116+
}
105117
}
106118
}
107119

src/resolver/const_evaluator.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,9 @@ pub fn evaluate_constants(mut index: Index) -> (Index, Vec<UnresolvableConstant>
140140
// there was an error during evaluation
141141
(Err(kind), _) => {
142142
//error during resolving
143+
dbg!(index.get_mut_const_expressions().find_const_expression(&candidate));
143144
unresolvable.push(
144-
UnresolvableConstant::new(candidate, kind.get_reason()).with_kind(kind.clone()),
145+
dbg!(UnresolvableConstant::new(candidate, kind.get_reason()).with_kind(kind.clone())),
145146
);
146147
index
147148
.get_mut_const_expressions()

0 commit comments

Comments
 (0)