From 91498fc6183f0da2e178034640af1c8416634ffe Mon Sep 17 00:00:00 2001 From: Mathias Rieder Date: Tue, 29 Nov 2022 16:19:55 +0000 Subject: [PATCH] initialize local VAR CONSTANT function vars aggregate local constant variables (in functions) used to have problems if they were not properly initialized. Instead of forcing an initializer, we fallback to the type's default value or zeroinitializer. added regression test for a previously failing situation fixes #634 --- src/codegen/generators/pou_generator.rs | 56 +++++------------ .../global_initializers.rs | 62 +++++++++++++++++++ ...initializer_gets_declared_initializer.snap | 34 ++++++++++ ..._initializer_gets_default_initializer.snap | 44 +++++++++++++ 4 files changed, 156 insertions(+), 40 deletions(-) create mode 100644 src/codegen/tests/initialization_test/snapshots/rusty__codegen__tests__initialization_test__global_initializers__global_constant_without_initializer_gets_declared_initializer.snap create mode 100644 src/codegen/tests/initialization_test/snapshots/rusty__codegen__tests__initialization_test__global_initializers__global_constant_without_initializer_gets_default_initializer.snap diff --git a/src/codegen/generators/pou_generator.rs b/src/codegen/generators/pou_generator.rs index 42c48c565d..965ebf31e7 100644 --- a/src/codegen/generators/pou_generator.rs +++ b/src/codegen/generators/pou_generator.rs @@ -92,32 +92,18 @@ pub fn generate_global_constants_for_pou_members<'ink>( ExpressionCodeGenerator::new_context_free(llvm, index, annotations, llvm_index); for variable in variables { let name = index::get_initializer_name(variable.get_qualified_name()); - let right_stmt = match variable.initial_value { - Some(..) => Some( - index - .get_const_expressions() - .maybe_get_constant_statement(&variable.initial_value) - .ok_or_else(|| { - Diagnostic::cannot_generate_initializer( - variable.get_qualified_name(), - variable.source_location.source_range.clone(), - ) - })?, - ), - None => None, - }; - - if let Some(stmt) = right_stmt { - if llvm_index.find_global_value(&name).is_none() { - //Get either a global initial value for the constant (For arrays) and copy it, - let value = if let Some(value) = - llvm_index.find_associated_initial_value(variable.get_qualified_name()) - { - value - } else { - exp_gen.generate_expression(stmt)? - }; - let variable_type = llvm_index.get_associated_type(variable.get_type_name())?; + let right_stmt = index + .get_const_expressions() + .maybe_get_constant_statement(&variable.initial_value); + + if right_stmt.is_some() && llvm_index.find_global_value(&name).is_none() { + let variable_type = llvm_index.get_associated_type(variable.get_type_name())?; + let value = if let Some(stmt) = right_stmt { + Some(exp_gen.generate_expression(stmt)?) + } else { + llvm_index.find_associated_initial_value(variable.get_qualified_name()) + }; + if let Some(value) = value { let global_value = llvm .create_global_variable(module, &name, variable_type) .make_constant() @@ -474,20 +460,10 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> { if let Some(left) = local_llvm_index .find_loaded_associated_variable_value(variable.get_qualified_name()) { - let right_stmt = match variable.initial_value { - Some(..) => Some( - self.index - .get_const_expressions() - .maybe_get_constant_statement(&variable.initial_value) - .ok_or_else(|| { - Diagnostic::cannot_generate_initializer( - variable.get_qualified_name(), - variable.source_location.source_range.clone(), - ) - })?, - ), - None => None, - }; + let right_stmt = self + .index + .get_const_expressions() + .maybe_get_constant_statement(&variable.initial_value); self.generate_variable_initializer(variable, left, right_stmt, &exp_gen)?; } else { return Err(Diagnostic::cannot_generate_initializer( diff --git a/src/codegen/tests/initialization_test/global_initializers.rs b/src/codegen/tests/initialization_test/global_initializers.rs index e89182cf7a..e8694382da 100644 --- a/src/codegen/tests/initialization_test/global_initializers.rs +++ b/src/codegen/tests/initialization_test/global_initializers.rs @@ -91,3 +91,65 @@ fn uninitialized_global_array() { insta::assert_snapshot!(result); } + +// regression for #634 +#[test] +fn global_constant_without_initializer_gets_default_initializer() { + let result = codegen( + " + FUNCTION main : DINT + VAR CONSTANT + cmd1 : commands; + myStr1 : STRING; + myArr1 : MyArr; + END_VAR + VAR_TEMP CONSTANT + cmd2 : commands; + //myStr2 : MyStr; + myArr2 : MyArr; + END_VAR + END_FUNCTION + + TYPE MyArr: ARRAY[0..3] OF INT; END_TYPE + + TYPE commands : + STRUCT + ReInit : BOOL; + Reset : BOOL; + END_STRUCT + END_TYPE + ", + ); + + // should initialize cmd1 & cmd2 with zeroinitializer + insta::assert_snapshot!(result); +} + +// regression for #634 +#[test] +fn global_constant_without_initializer_gets_declared_initializer() { + let result = codegen( + " + FUNCTION main : DINT + VAR CONSTANT + cmd1 : commands; + var1 : INT; + END_VAR + VAR CONSTANT + cmd2 : commands; + var2 : INT; + END_VAR + END_FUNCTION + + TYPE commands : + STRUCT + ReInit : BOOL := TRUE; + Reset : BOOL := FALSE; + END_STRUCT + END_TYPE + ", + ); + + //should initialize cmd1 and cmd2 with @__comamnds__init + insta::assert_snapshot!(result); +} diff --git a/src/codegen/tests/initialization_test/snapshots/rusty__codegen__tests__initialization_test__global_initializers__global_constant_without_initializer_gets_declared_initializer.snap b/src/codegen/tests/initialization_test/snapshots/rusty__codegen__tests__initialization_test__global_initializers__global_constant_without_initializer_gets_declared_initializer.snap new file mode 100644 index 0000000000..ff3fe8f124 --- /dev/null +++ b/src/codegen/tests/initialization_test/snapshots/rusty__codegen__tests__initialization_test__global_initializers__global_constant_without_initializer_gets_declared_initializer.snap @@ -0,0 +1,34 @@ +--- +source: src/codegen/tests/initialization_test/global_initializers.rs +expression: result +--- +; ModuleID = 'main' +source_filename = "main" + +%commands = type { i8, i8 } + +@__commands__init = unnamed_addr constant %commands { i8 1, i8 0 } + +define i32 @main() { +entry: + %cmd1 = alloca %commands, align 8 + %var1 = alloca i16, align 2 + %cmd2 = alloca %commands, align 8 + %var2 = alloca i16, align 2 + %main = alloca i32, align 4 + %0 = bitcast %commands* %cmd1 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%commands, %commands* @__commands__init, i32 0, i32 0), i64 ptrtoint (%commands* getelementptr (%commands, %commands* null, i32 1) to i64), i1 false) + store i16 0, i16* %var1, align 2 + %1 = bitcast %commands* %cmd2 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %1, i8* align 1 getelementptr inbounds (%commands, %commands* @__commands__init, i32 0, i32 0), i64 ptrtoint (%commands* getelementptr (%commands, %commands* null, i32 1) to i64), i1 false) + store i16 0, i16* %var2, align 2 + store i32 0, i32* %main, align 4 + %main_ret = load i32, i32* %main, align 4 + ret i32 %main_ret +} + +; Function Attrs: argmemonly nofree nounwind willreturn +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0 + +attributes #0 = { argmemonly nofree nounwind willreturn } + diff --git a/src/codegen/tests/initialization_test/snapshots/rusty__codegen__tests__initialization_test__global_initializers__global_constant_without_initializer_gets_default_initializer.snap b/src/codegen/tests/initialization_test/snapshots/rusty__codegen__tests__initialization_test__global_initializers__global_constant_without_initializer_gets_default_initializer.snap new file mode 100644 index 0000000000..50524175db --- /dev/null +++ b/src/codegen/tests/initialization_test/snapshots/rusty__codegen__tests__initialization_test__global_initializers__global_constant_without_initializer_gets_default_initializer.snap @@ -0,0 +1,44 @@ +--- +source: src/codegen/tests/initialization_test/global_initializers.rs +expression: result +--- +; ModuleID = 'main' +source_filename = "main" + +%commands = type { i8, i8 } + +@__commands__init = unnamed_addr constant %commands zeroinitializer +@__main.myStr1__init = unnamed_addr constant [81 x i8] zeroinitializer + +define i32 @main() { +entry: + %cmd1 = alloca %commands, align 8 + %myStr1 = alloca [81 x i8], align 1 + %myArr1 = alloca [4 x i16], align 2 + %cmd2 = alloca %commands, align 8 + %myArr2 = alloca [4 x i16], align 2 + %main = alloca i32, align 4 + %0 = bitcast %commands* %cmd1 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 getelementptr inbounds (%commands, %commands* @__commands__init, i32 0, i32 0), i64 ptrtoint (%commands* getelementptr (%commands, %commands* null, i32 1) to i64), i1 false) + %1 = bitcast [81 x i8]* %myStr1 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %1, i8* align 1 getelementptr inbounds ([81 x i8], [81 x i8]* @__main.myStr1__init, i32 0, i32 0), i64 ptrtoint ([81 x i8]* getelementptr ([81 x i8], [81 x i8]* null, i32 1) to i64), i1 false) + %2 = bitcast [4 x i16]* %myArr1 to i8* + call void @llvm.memset.p0i8.i64(i8* align 1 %2, i8 0, i64 ptrtoint ([4 x i16]* getelementptr ([4 x i16], [4 x i16]* null, i32 1) to i64), i1 false) + %3 = bitcast %commands* %cmd2 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %3, i8* align 1 getelementptr inbounds (%commands, %commands* @__commands__init, i32 0, i32 0), i64 ptrtoint (%commands* getelementptr (%commands, %commands* null, i32 1) to i64), i1 false) + %4 = bitcast [4 x i16]* %myArr2 to i8* + call void @llvm.memset.p0i8.i64(i8* align 1 %4, i8 0, i64 ptrtoint ([4 x i16]* getelementptr ([4 x i16], [4 x i16]* null, i32 1) to i64), i1 false) + store i32 0, i32* %main, align 4 + %main_ret = load i32, i32* %main, align 4 + ret i32 %main_ret +} + +; Function Attrs: argmemonly nofree nounwind willreturn +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0 + +; Function Attrs: argmemonly nofree nounwind willreturn writeonly +declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) #1 + +attributes #0 = { argmemonly nofree nounwind willreturn } +attributes #1 = { argmemonly nofree nounwind willreturn writeonly } +