Skip to content

Commit 15eb67e

Browse files
authored
feat: Aliased Hardware Access Variables (#1265)
feat: Aliased Hardware Access Variables Adds support to create new hardware variables by declaring a global variable with the address For example : VAR_GLOBAL heatSwitch AT %IX1.2.3.4 : BOOL; END_VAR will create a variable __PI_1_2_3_4 : BOOL and map the heatSwitch variable to it. A runtime can then point the __PI_1_2_3_4 to a real hardware value. This PR still does not allow declaring hardware addresses with no associated variables. Assigning variables inside POUs is also not possible
1 parent 41968d3 commit 15eb67e

9 files changed

+587
-15
lines changed

compiler/plc_ast/src/ast.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,20 @@ impl DataTypeDeclaration {
471471
let DataTypeDeclaration::DataTypeReference { referenced_type, .. } = self else { return None };
472472
Some(referenced_type.to_owned())
473473
}
474+
475+
pub fn get_inner_pointer_ty(&self) -> Option<DataTypeDeclaration> {
476+
match self {
477+
DataTypeDeclaration::DataTypeReference { .. } => Some(self.clone()),
478+
479+
DataTypeDeclaration::DataTypeDefinition { data_type, .. } => {
480+
if let DataType::PointerType { referenced_type, .. } = data_type {
481+
return referenced_type.get_inner_pointer_ty();
482+
}
483+
484+
None
485+
}
486+
}
487+
}
474488
}
475489

476490
#[derive(PartialEq)]

compiler/plc_ast/src/pre_processor.rs

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use plc_util::convention::internal_type_name;
77
use crate::{
88
ast::{
99
flatten_expression_list, Assignment, AstFactory, AstNode, AstStatement, CompilationUnit, DataType,
10-
DataTypeDeclaration, Operator, Pou, UserTypeDeclaration, Variable,
10+
DataTypeDeclaration, DirectAccessType, HardwareAccess, HardwareAccessType, Operator, Pou,
11+
UserTypeDeclaration, Variable, VariableBlockType,
1112
},
1213
literals::AstLiteral,
1314
provider::IdProvider,
@@ -21,13 +22,13 @@ pub fn pre_process(unit: &mut CompilationUnit, mut id_provider: IdProvider) {
2122
let generic_types = preprocess_generic_structs(pou);
2223
unit.user_types.extend(generic_types);
2324

24-
let all_variables = pou
25+
let local_variables = pou
2526
.variable_blocks
2627
.iter_mut()
2728
.flat_map(|it| it.variables.iter_mut())
2829
.filter(|it| should_generate_implicit_type(it));
2930

30-
for var in all_variables {
31+
for var in local_variables {
3132
pre_process_variable_data_type(pou.name.as_str(), var, &mut unit.user_types)
3233
}
3334

@@ -36,15 +37,7 @@ pub fn pre_process(unit: &mut CompilationUnit, mut id_provider: IdProvider) {
3637
}
3738

3839
//process all variables from GVLs
39-
let all_variables = unit
40-
.global_vars
41-
.iter_mut()
42-
.flat_map(|gv| gv.variables.iter_mut())
43-
.filter(|it| should_generate_implicit_type(it));
44-
45-
for var in all_variables {
46-
pre_process_variable_data_type("global", var, &mut unit.user_types)
47-
}
40+
process_global_variables(unit, &mut id_provider);
4841

4942
//process all variables in dataTypes
5043
let mut new_types = vec![];
@@ -150,6 +143,68 @@ pub fn pre_process(unit: &mut CompilationUnit, mut id_provider: IdProvider) {
150143
unit.user_types.append(&mut new_types);
151144
}
152145

146+
fn process_global_variables(unit: &mut CompilationUnit, id_provider: &mut IdProvider) {
147+
let mut mangled_globals = Vec::new();
148+
149+
for global_var in unit.global_vars.iter_mut().flat_map(|block| block.variables.iter_mut()) {
150+
let ref_ty = global_var.data_type_declaration.get_inner_pointer_ty();
151+
152+
if should_generate_implicit_type(global_var) {
153+
pre_process_variable_data_type("global", global_var, &mut unit.user_types)
154+
}
155+
156+
// In any case, we have to inject initializers into aliased hardware access variables
157+
if let Some(ref node) = global_var.address {
158+
if let AstStatement::HardwareAccess(HardwareAccess { direction, access, address }) = &node.stmt {
159+
let direction = match direction {
160+
HardwareAccessType::Input | HardwareAccessType::Output => "PI",
161+
HardwareAccessType::Memory => "M",
162+
HardwareAccessType::Global => "G",
163+
};
164+
let name = format!(
165+
"__{direction}_{}",
166+
address
167+
.iter()
168+
.flat_map(|node| node.get_literal_integer_value())
169+
.map(|val| val.to_string())
170+
.collect::<Vec<_>>()
171+
.join("_")
172+
);
173+
174+
// %I*: DWORD; should not be declared at this stage, it is just skipped
175+
if matches!(access, DirectAccessType::Template) {
176+
continue;
177+
}
178+
179+
let mangled_initializer = AstFactory::create_member_reference(
180+
AstFactory::create_identifier(&name, SourceLocation::internal(), id_provider.next_id()),
181+
None,
182+
id_provider.next_id(),
183+
);
184+
185+
global_var.initializer = Some(mangled_initializer);
186+
187+
let internal_mangled_var = Variable {
188+
name,
189+
data_type_declaration: ref_ty.unwrap_or(global_var.data_type_declaration.clone()),
190+
initializer: None,
191+
address: None,
192+
location: SourceLocation::internal(),
193+
};
194+
mangled_globals.push(internal_mangled_var);
195+
}
196+
}
197+
}
198+
199+
if let Some(block) =
200+
unit.global_vars.iter_mut().find(|block| block.variable_block_type == VariableBlockType::Global)
201+
{
202+
for new_var in mangled_globals {
203+
block.variables.push(new_var);
204+
}
205+
}
206+
}
207+
153208
fn build_enum_initializer(
154209
last_name: &Option<String>,
155210
location: &SourceLocation,

src/codegen/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder
2+
mod address_tests;
23
mod code_gen_tests;
34
mod codegen_error_messages_tests;
45
mod compare_instructions_tests;

src/codegen/tests/address_tests.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
use insta::assert_snapshot;
2+
3+
use crate::test_utils::tests::codegen;
4+
5+
#[test]
6+
fn aliased_address_in_global_generated() {
7+
let res = codegen(
8+
r"
9+
VAR_GLOBAL
10+
foo AT %IX1.2.3.4 : BOOL;
11+
END_VAR
12+
",
13+
);
14+
15+
assert_snapshot!(res, @r###"
16+
; ModuleID = '<internal>'
17+
source_filename = "<internal>"
18+
19+
@foo = global i8* null, section "var-$RUSTY$foo:pu8"
20+
@__PI_1_2_3_4 = global i8 0, section "var-$RUSTY$__PI_1_2_3_4:u8"
21+
; ModuleID = '__init___testproject'
22+
source_filename = "__init___testproject"
23+
24+
@__PI_1_2_3_4 = external global i8, section "var-$RUSTY$__PI_1_2_3_4:u8"
25+
@foo = external global i8*, section "var-$RUSTY$foo:pu8"
26+
27+
define void @__init___testproject() section "fn-$RUSTY$__init___testproject:v" {
28+
entry:
29+
store i8* @__PI_1_2_3_4, i8** @foo, align 8
30+
ret void
31+
}
32+
"###);
33+
}
34+
35+
#[test]
36+
fn duplicate_aliased_address_in_global_generated() {
37+
let res = codegen(
38+
r"
39+
VAR_GLOBAL
40+
foo AT %IX1.2.3.4 : BOOL;
41+
baz AT %IX1.2.3.4 : BOOL;
42+
END_VAR
43+
",
44+
);
45+
46+
assert_snapshot!(res, @r###"
47+
; ModuleID = '<internal>'
48+
source_filename = "<internal>"
49+
50+
@foo = global i8* null, section "var-$RUSTY$foo:pu8"
51+
@__PI_1_2_3_4 = global i8 0, section "var-$RUSTY$__PI_1_2_3_4:u8"
52+
@baz = global i8* null, section "var-$RUSTY$baz:pu8"
53+
; ModuleID = '__init___testproject'
54+
source_filename = "__init___testproject"
55+
56+
@__PI_1_2_3_4 = external global i8, section "var-$RUSTY$__PI_1_2_3_4:u8"
57+
@foo = external global i8*, section "var-$RUSTY$foo:pu8"
58+
@baz = external global i8*, section "var-$RUSTY$baz:pu8"
59+
60+
define void @__init___testproject() section "fn-$RUSTY$__init___testproject:v" {
61+
entry:
62+
store i8* @__PI_1_2_3_4, i8** @foo, align 8
63+
store i8* @__PI_1_2_3_4, i8** @baz, align 8
64+
ret void
65+
}
66+
"###);
67+
}
68+
69+
#[test]
70+
fn address_variable_used_with_symbolic_name() {
71+
let res = codegen(
72+
r"
73+
VAR_GLOBAL
74+
foo AT %IX1.2.3.4 : BOOL;
75+
baz AT %IX1.2.3.4 : BOOL;
76+
END_VAR
77+
78+
PROGRAM mainProg
79+
foo := FALSE;
80+
baz := TRUE;
81+
END_PROGRAM
82+
",
83+
);
84+
85+
assert_snapshot!(res, @r###"
86+
; ModuleID = '<internal>'
87+
source_filename = "<internal>"
88+
89+
%mainProg = type {}
90+
91+
@foo = global i8* null, section "var-$RUSTY$foo:pu8"
92+
@__PI_1_2_3_4 = global i8 0, section "var-$RUSTY$__PI_1_2_3_4:u8"
93+
@baz = global i8* null, section "var-$RUSTY$baz:pu8"
94+
@mainProg_instance = global %mainProg zeroinitializer, section "var-$RUSTY$mainProg_instance:r0"
95+
96+
define void @mainProg(%mainProg* %0) section "fn-$RUSTY$mainProg:v" {
97+
entry:
98+
%deref = load i8*, i8** @foo, align 8
99+
store i8 0, i8* %deref, align 1
100+
%deref1 = load i8*, i8** @baz, align 8
101+
store i8 1, i8* %deref1, align 1
102+
ret void
103+
}
104+
; ModuleID = '__initializers'
105+
source_filename = "__initializers"
106+
107+
%mainProg = type {}
108+
109+
@mainProg_instance = external global %mainProg, section "var-$RUSTY$mainProg_instance:r0"
110+
111+
define void @__init_mainprog(%mainProg* %0) section "fn-$RUSTY$__init_mainprog:v[pr0]" {
112+
entry:
113+
%self = alloca %mainProg*, align 8
114+
store %mainProg* %0, %mainProg** %self, align 8
115+
ret void
116+
}
117+
118+
declare void @mainProg(%mainProg*) section "fn-$RUSTY$mainProg:v"
119+
; ModuleID = '__init___testproject'
120+
source_filename = "__init___testproject"
121+
122+
%mainProg = type {}
123+
124+
@__PI_1_2_3_4 = external global i8, section "var-$RUSTY$__PI_1_2_3_4:u8"
125+
@foo = external global i8*, section "var-$RUSTY$foo:pu8"
126+
@baz = external global i8*, section "var-$RUSTY$baz:pu8"
127+
@mainProg_instance = external global %mainProg, section "var-$RUSTY$mainProg_instance:r0"
128+
129+
define void @__init___testproject() section "fn-$RUSTY$__init___testproject:v" {
130+
entry:
131+
store i8* @__PI_1_2_3_4, i8** @foo, align 8
132+
store i8* @__PI_1_2_3_4, i8** @baz, align 8
133+
call void @__init_mainprog(%mainProg* @mainProg_instance)
134+
ret void
135+
}
136+
137+
declare void @__init_mainprog(%mainProg*) section "fn-$RUSTY$__init_mainprog:v[pr0]"
138+
139+
declare void @mainProg(%mainProg*) section "fn-$RUSTY$mainProg:v"
140+
"###);
141+
}

0 commit comments

Comments
 (0)