Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
652 changes: 336 additions & 316 deletions compiler/plc_ast/src/pre_processor.rs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ extern "C" {

typedef int16_t __global_gVarArrayOfArrayOfIntArray__[12];

typedef __global_gVarArrayOfArrayOfIntArray__ __global_gVarArrayOfArrayOfIntArray_[12];

typedef int16_t __global_gVarArrayOfIntArray_[12];

typedef __global_gVarArrayOfArrayOfIntArray__ __global_gVarArrayOfArrayOfIntArray_[12];

extern char gVarString[256];
extern int16_t gVarWString[6001];
extern int16_t gVarIntArray[12];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ expression: "serde_json::to_string_pretty(&prepared_header_data).expect(\"Failed
}
},
{
"data_type": "__global_gVarArrayOfArrayOfIntArray__",
"name": "__global_gVarArrayOfArrayOfIntArray_",
"data_type": "int16_t",
"name": "__global_gVarArrayOfIntArray_",
"variable_type": {
"Array": 12
}
},
{
"data_type": "int16_t",
"name": "__global_gVarArrayOfIntArray_",
"data_type": "__global_gVarArrayOfArrayOfIntArray__",
"name": "__global_gVarArrayOfArrayOfIntArray_",
"variable_type": {
"Array": 12
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ expression: "&generated_header.get_contents()"
extern "C" {
#endif

typedef int16_t __fnThatUsesStructWithComplexTypes_varArrayOfIntArray_[15];

typedef int16_t __StructWithComplexTypes_arrayOfIntArrayField_[10];

typedef int16_t __fnThatUsesStructWithComplexTypes_varArrayOfIntArray_[15];

typedef int32_t ComplexEnumType;
#define ComplexEnumType_orange ((ComplexEnumType)10)
#define ComplexEnumType_yellow ((ComplexEnumType)20)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ expression: "serde_json::to_string_pretty(&prepared_header_data).expect(\"Failed
"aliases": [
{
"data_type": "int16_t",
"name": "__fnThatUsesStructWithComplexTypes_varArrayOfIntArray_",
"name": "__StructWithComplexTypes_arrayOfIntArrayField_",
"variable_type": {
"Array": 15
"Array": 10
}
},
{
"data_type": "int16_t",
"name": "__StructWithComplexTypes_arrayOfIntArrayField_",
"name": "__fnThatUsesStructWithComplexTypes_varArrayOfIntArray_",
"variable_type": {
"Array": 10
"Array": 15
}
}
],
Expand Down
57 changes: 55 additions & 2 deletions compiler/plc_lowering/src/initializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,11 +477,14 @@ impl InitLoweringPolicy {
///
/// Resolution order:
/// 1) Struct literals on struct-typed fields are decomposed.
/// 2) Reference-typed fields use `REF=` (unwrapping `REF(...)` if present).
/// 3) Otherwise use direct `:=` assignment.
/// 2) Alias-typed fields (e.g. hardware-mapped `AT %IX...`) use `REF=`.
/// 3) Reference-typed fields use `REF=` (unwrapping `REF(...)` if present).
/// 4) Otherwise use direct `:=` assignment.
fn for_struct_field(variable: &Variable, initializer: &AstNode, index: &Index) -> Self {
if is_struct_type(variable, index) && initializer.is_struct_literal_initializer() {
InitLoweringPolicy::StructDecompose
} else if is_alias_type(variable, index) {
InitLoweringPolicy::RefAssign(Box::new(initializer.clone()))
} else if is_reference_type(variable, index) {
let ref_rhs = extract_ref_call_argument(initializer).unwrap_or(initializer).clone();
InitLoweringPolicy::RefAssign(Box::new(ref_rhs))
Expand All @@ -507,6 +510,22 @@ fn is_reference_type(variable: &Variable, index: &Index) -> bool {
.is_some_and(|ti| ti.is_reference_to())
}

fn is_alias_type(variable: &Variable, index: &Index) -> bool {
// Check inline definition first (before pre-processing resolves the type name)
if let DataTypeDeclaration::Definition { data_type, .. } = &variable.data_type_declaration {
if let DataType::PointerType { auto_deref: Some(AutoDerefType::Alias), .. } = data_type.as_ref() {
return true;
}
}

// Fall back to index lookup for pre-processed types
variable
.data_type_declaration
.get_referenced_type()
.and_then(|tn| index.find_effective_type_info(tn))
.is_some_and(|ti| ti.is_alias())
}

/// Checks if a variable is an alias or reference variable that needs ADR() wrapping
/// (declared with AT syntax, e.g., `px AT x : DINT`, or `REFERENCE TO ... REF= ...`)
fn is_alias_or_reference_variable(variable: &Variable, index: &Index) -> bool {
Expand Down Expand Up @@ -1799,4 +1818,38 @@ mod tests {
self.FB_INIT()
");
}

#[test]
fn struct_member_with_hardware_address_initialized_in_constructor() {
let src = r#"
TYPE NodeB : STRUCT
c AT %IX1.2.3.4 : BOOL;
END_STRUCT
END_TYPE

TYPE NodeA : STRUCT
b : NodeB;
END_STRUCT
END_TYPE

VAR_GLOBAL
myNode : NodeA;
END_VAR
"#;

let initializer = parse_and_init(src);
// NodeB's constructor should initialize its hardware-mapped field with REF=
insta::assert_snapshot!(print_body_to_string(initializer.constructors.get("NodeB").unwrap()), @r"
intern:
__NodeB_c__ctor(self.c)
self.c REF= __PI_1_2_3_4
");
// NodeA's constructor should call NodeB's constructor for its member
insta::assert_snapshot!(print_body_to_string(initializer.constructors.get("NodeA").unwrap()), @r"
intern:
NodeB__ctor(self.b)
");
// Global constructor should call NodeA's constructor
insta::assert_snapshot!(print_to_string(&initializer.global_constructor), @"NodeA__ctor(myNode)");
}
}
36 changes: 36 additions & 0 deletions src/codegen/tests/address_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,39 @@ fn address_used_in_body() {
}
"#);
}

#[test]
fn struct_member_with_hardware_address() {
let res = codegen(
r"
TYPE NodeB : STRUCT
c AT %IX1.2.3.4 : BOOL;
END_STRUCT
END_TYPE

TYPE NodeA : STRUCT
b : NodeB;
END_STRUCT
END_TYPE

VAR_GLOBAL
myNode : NodeA;
END_VAR
",
);

// The backing global __PI_1_2_3_4 is created for the hardware address.
// NodeB.c becomes a pointer initialized to &__PI_1_2_3_4 in NodeB__ctor (separate module).
filtered_assert_snapshot!(res, @r#"
; ModuleID = '<internal>'
source_filename = "<internal>"
target datalayout = "[filtered]"
target triple = "[filtered]"

%NodeA = type { %NodeB }
%NodeB = type { ptr }

@myNode = global %NodeA zeroinitializer
@__PI_1_2_3_4 = global i8 0
"#);
}
50 changes: 25 additions & 25 deletions src/codegen/tests/debug_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -702,21 +702,21 @@ fn dbg_declare_has_valid_metadata_references_for_methods() {
ret void, !dbg !15
}

define void @__fb___vtable__ctor(ptr %0) {
define void @____vtable_fb___body__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !15
store ptr %0, ptr %self, align [filtered], !dbg !15
ret void, !dbg !15
}

define void @____vtable_fb___body__ctor(ptr %0) {
define void @____vtable_fb_foo__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !15
store ptr %0, ptr %self, align [filtered], !dbg !15
ret void, !dbg !15
}

define void @____vtable_fb_foo__ctor(ptr %0) {
define void @__fb___vtable__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !15
store ptr %0, ptr %self, align [filtered], !dbg !15
Expand Down Expand Up @@ -1058,28 +1058,28 @@ END_FUNCTION
ret void, !dbg !58
}

define void @__main_arr__ctor(ptr %0) {
define void @__struct__inner_arr__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !58
store ptr %0, ptr %self, align [filtered], !dbg !58
ret void, !dbg !58
}

define void @__struct__inner_arr__ctor(ptr %0) {
define void @__struct__arr__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !58
store ptr %0, ptr %self, align [filtered], !dbg !58
ret void, !dbg !58
}

define void @__struct__arr__ctor(ptr %0) {
define void @__inner_arr__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !58
store ptr %0, ptr %self, align [filtered], !dbg !58
ret void, !dbg !58
}

define void @__inner_arr__ctor(ptr %0) {
define void @__main_arr__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !58
store ptr %0, ptr %self, align [filtered], !dbg !58
Expand Down Expand Up @@ -1341,28 +1341,28 @@ fn test_debug_info_regular_pointer_types() {
ret void
}

define void @__global_array_ptr___ctor(ptr %0) {
define void @__global_array_ptr__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered]
store ptr %0, ptr %self, align [filtered]
ret void
}

define void @__global_array_ptr__ctor(ptr %0) {
define void @__global_struct_ptr__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered]
store ptr %0, ptr %self, align [filtered]
ret void
}

define void @__global_struct_ptr__ctor(ptr %0) {
define void @__global_string_ptr__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered]
store ptr %0, ptr %self, align [filtered]
ret void
}

define void @__global_string_ptr__ctor(ptr %0) {
define void @__global_array_ptr___ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered]
store ptr %0, ptr %self, align [filtered]
Expand Down Expand Up @@ -1710,35 +1710,35 @@ fn test_debug_info_mixed_pointer_types() {
ret void, !dbg !43
}

define void @__mixed_ptr_local_ptr__ctor(ptr %0) {
define void @__global_regular_ptr__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !43
store ptr %0, ptr %self, align [filtered], !dbg !43
ret void, !dbg !43
}

define void @__mixed_ptr_local_ref__ctor(ptr %0) {
define void @__global_alias_var__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !43
store ptr %0, ptr %self, align [filtered], !dbg !43
ret void, !dbg !43
}

define void @__global_regular_ptr__ctor(ptr %0) {
define void @__mixed_ptr_local_ptr__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !43
store ptr %0, ptr %self, align [filtered], !dbg !43
ret void, !dbg !43
}

define void @__global_alias_var___ctor(ptr %0) {
define void @__mixed_ptr_local_ref__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !43
store ptr %0, ptr %self, align [filtered], !dbg !43
ret void, !dbg !43
}

define void @__global_alias_var__ctor(ptr %0) {
define void @__global_alias_var___ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !43
store ptr %0, ptr %self, align [filtered], !dbg !43
Expand Down Expand Up @@ -1882,63 +1882,63 @@ fn test_debug_info_auto_deref_reference_to_pointers() {
ret void, !dbg !56
}

define void @__test_with_reference_params_ref_param__ctor(ptr %0) {
define void @__global_basic_reference__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !56
store ptr %0, ptr %self, align [filtered], !dbg !56
ret void, !dbg !56
}

define void @__test_with_reference_params_array_ref_param___ctor(ptr %0) {
define void @__global_array_reference__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !56
store ptr %0, ptr %self, align [filtered], !dbg !56
ret void, !dbg !56
}

define void @__test_with_reference_params_array_ref_param__ctor(ptr %0) {
define void @__global_struct_reference__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !56
store ptr %0, ptr %self, align [filtered], !dbg !56
ret void, !dbg !56
}

define void @__test_with_reference_params_local_reference__ctor(ptr %0) {
define void @__global_string_reference__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !56
store ptr %0, ptr %self, align [filtered], !dbg !56
ret void, !dbg !56
}

define void @__global_basic_reference__ctor(ptr %0) {
define void @__test_with_reference_params_ref_param__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !56
store ptr %0, ptr %self, align [filtered], !dbg !56
ret void, !dbg !56
}

define void @__global_array_reference___ctor(ptr %0) {
define void @__test_with_reference_params_array_ref_param__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !56
store ptr %0, ptr %self, align [filtered], !dbg !56
ret void, !dbg !56
}

define void @__global_array_reference__ctor(ptr %0) {
define void @__test_with_reference_params_local_reference__ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !56
store ptr %0, ptr %self, align [filtered], !dbg !56
ret void, !dbg !56
}

define void @__global_struct_reference__ctor(ptr %0) {
define void @__global_array_reference___ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !56
store ptr %0, ptr %self, align [filtered], !dbg !56
ret void, !dbg !56
}

define void @__global_string_reference__ctor(ptr %0) {
define void @__test_with_reference_params_array_ref_param___ctor(ptr %0) {
entry:
%self = alloca ptr, align [filtered], !dbg !56
store ptr %0, ptr %self, align [filtered], !dbg !56
Expand Down
Loading
Loading