Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initialize local VAR CONSTANT function vars #669

Merged
merged 1 commit into from
Dec 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 16 additions & 40 deletions src/codegen/generators/pou_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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(
Expand Down
62 changes: 62 additions & 0 deletions src/codegen/tests/initialization_test/global_initializers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
@@ -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 }

Original file line number Diff line number Diff line change
@@ -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 }