diff --git a/src/codegen/generators/statement_generator.rs b/src/codegen/generators/statement_generator.rs index 30d125f57f..d9edbd130c 100644 --- a/src/codegen/generators/statement_generator.rs +++ b/src/codegen/generators/statement_generator.rs @@ -1,20 +1,23 @@ // Copyright (c) 2020 Ghaith Hachem and Mathias Rieder use super::{ - expression_generator::{to_i1, ExpressionCodeGenerator}, + expression_generator::{to_i1, ExpressionCodeGenerator, ExpressionValue}, llvm::Llvm, }; use crate::{ - codegen::debug::Debug, - codegen::{debug::DebugBuilderEnum, LlvmTypedIndex}, + codegen::{ + debug::{Debug, DebugBuilderEnum}, + llvm_typesystem::cast_if_needed, + LlvmTypedIndex, + }, index::{ImplementationIndexEntry, Index}, resolver::{AnnotationMap, AstAnnotations, StatementAnnotation}, - typesystem::DataTypeInformation, + typesystem::{get_bigger_type, DataTypeInformation, DINT_TYPE}, }; use inkwell::{ basic_block::BasicBlock, builder::Builder, context::Context, - values::{BasicValueEnum, FunctionValue, PointerValue}, + values::{FunctionValue, PointerValue}, }; use plc_ast::{ ast::{ @@ -325,117 +328,107 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> { body: &[AstNode], ) -> Result<(), Diagnostic> { let (builder, current_function, context) = self.get_llvm_deps(); - self.generate_assignment_statement(counter, start)?; - let condition_check = context.append_basic_block(current_function, "condition_check"); - let for_body = context.append_basic_block(current_function, "for_body"); - let increment_block = context.append_basic_block(current_function, "increment"); - let continue_block = context.append_basic_block(current_function, "continue"); - - //Generate an initial jump to the for condition - builder.build_unconditional_branch(condition_check); - - //Check loop condition - builder.position_at_end(condition_check); let exp_gen = self.create_expr_generator(); - let counter_statement = exp_gen.generate_expression(counter)?; - //. / and_2 \ - //. / and 1 \ - //. (counter_end_le && counter_start_ge) || (counter_end_ge && counter_start_le) - let or_eval = self.generate_compare_expression(counter, end, start, &exp_gen)?; + let end_ty = self.annotations.get_type_or_void(end, self.index); + let counter_ty = self.annotations.get_type_or_void(counter, self.index); + let cast_target_ty = get_bigger_type(self.index.get_type_or_panic(DINT_TYPE), counter_ty, self.index); + let cast_target_llty = self.llvm_index.find_associated_type(cast_target_ty.get_name()).unwrap(); + + let step_ty = by_step.as_ref().map(|it| { + self.register_debug_location(it); + self.annotations.get_type_or_void(it, self.index) + }); + + let eval_step = || { + step_ty.map_or_else( + || self.llvm.create_const_numeric(&cast_target_llty, "1", SourceLocation::undefined()), + |step_ty| { + let step = exp_gen.generate_expression(by_step.as_ref().unwrap())?; + Ok(cast_if_needed!(exp_gen, cast_target_ty, step_ty, step, None)) + }, + ) + }; - builder.build_conditional_branch(to_i1(or_eval.into_int_value(), builder), for_body, continue_block); + let predicate_incrementing = context.append_basic_block(current_function, "predicate_sle"); + let predicate_decrementing = context.append_basic_block(current_function, "predicate_sge"); + let loop_body = context.append_basic_block(current_function, "loop"); + let increment = context.append_basic_block(current_function, "increment"); + let afterloop = context.append_basic_block(current_function, "continue"); - //Enter the for loop - builder.position_at_end(for_body); - let body_generator = StatementCodeGenerator { - current_loop_exit: Some(continue_block), - current_loop_continue: Some(increment_block), + self.generate_assignment_statement(counter, start)?; + let counter = exp_gen.generate_lvalue(counter)?; + + // generate loop predicate selector. since `STEP` can be a reference, this needs to be a runtime eval + // XXX(mhasel): IR could possibly be improved by generating phi instructions. + // Candidate for frontend optimization for builds without optimization when `STEP` + // is a compile-time constant + let is_incrementing = builder.build_int_compare( + inkwell::IntPredicate::SGT, + eval_step()?.into_int_value(), + self.llvm + .create_const_numeric(&cast_target_llty, "0", SourceLocation::undefined())? + .into_int_value(), + "is_incrementing", + ); + builder.build_conditional_branch(is_incrementing, predicate_incrementing, predicate_decrementing); + // generate predicates for incrementing and decrementing counters + let generate_predicate = |predicate| { + builder.position_at_end(match predicate { + inkwell::IntPredicate::SLE => predicate_incrementing, + inkwell::IntPredicate::SGE => predicate_decrementing, + _ => unreachable!(), + }); + + let end = exp_gen.generate_expression_value(end).unwrap(); + let end_value = match end { + ExpressionValue::LValue(ptr) => builder.build_load(ptr, ""), + ExpressionValue::RValue(val) => val, + }; + let counter_value = builder.build_load(counter, ""); + let cmp = builder.build_int_compare( + predicate, + cast_if_needed!(exp_gen, cast_target_ty, counter_ty, counter_value, None).into_int_value(), + cast_if_needed!(exp_gen, cast_target_ty, end_ty, end_value, None).into_int_value(), + "condition", + ); + builder.build_conditional_branch(cmp, loop_body, afterloop); + }; + generate_predicate(inkwell::IntPredicate::SLE); + generate_predicate(inkwell::IntPredicate::SGE); + + // generate loop body + builder.position_at_end(loop_body); + let body_builder = StatementCodeGenerator { + current_loop_continue: Some(increment), + current_loop_exit: Some(afterloop), load_prefix: self.load_prefix.clone(), load_suffix: self.load_suffix.clone(), ..*self }; - body_generator.generate_body(body)?; - builder.build_unconditional_branch(increment_block); - - //Increment - builder.position_at_end(increment_block); - let expression_generator = self.create_expr_generator(); - let step_by_value = by_step.as_ref().map_or_else( - || { - self.llvm.create_const_numeric( - &counter_statement.get_type(), - "1", - SourceLocation::undefined(), - ) - }, - |step| { - self.register_debug_location(step); - expression_generator.generate_expression(step) - }, - )?; - - let next = builder.build_int_add( - counter_statement.into_int_value(), - step_by_value.into_int_value(), - "tmpVar", + body_builder.generate_body(body)?; + + // increment counter + builder.build_unconditional_branch(increment); + builder.position_at_end(increment); + let counter_value = builder.build_load(counter, ""); + let inc = inkwell::values::BasicValue::as_basic_value_enum(&builder.build_int_add( + eval_step()?.into_int_value(), + cast_if_needed!(exp_gen, cast_target_ty, counter_ty, counter_value, None).into_int_value(), + "next", + )); + builder.build_store( + counter, + cast_if_needed!(exp_gen, counter_ty, cast_target_ty, inc, None).into_int_value(), ); - let ptr = expression_generator.generate_lvalue(counter)?; - builder.build_store(ptr, next); - - //Loop back - builder.build_unconditional_branch(condition_check); - - //Continue - builder.position_at_end(continue_block); - + // check condition + builder.build_conditional_branch(is_incrementing, predicate_incrementing, predicate_decrementing); + // continue + builder.position_at_end(afterloop); Ok(()) } - fn generate_compare_expression( - &'a self, - counter: &AstNode, - end: &AstNode, - start: &AstNode, - exp_gen: &'a ExpressionCodeGenerator, - ) -> Result, Diagnostic> { - let bool_id = self.annotations.get_bool_id(); - let counter_end_ge = AstFactory::create_binary_expression( - counter.clone(), - Operator::GreaterOrEqual, - end.clone(), - bool_id, - ); - let counter_start_ge = AstFactory::create_binary_expression( - counter.clone(), - Operator::GreaterOrEqual, - start.clone(), - bool_id, - ); - let counter_end_le = AstFactory::create_binary_expression( - counter.clone(), - Operator::LessOrEqual, - end.clone(), - bool_id, - ); - let counter_start_le = AstFactory::create_binary_expression( - counter.clone(), - Operator::LessOrEqual, - start.clone(), - bool_id, - ); - let and_1 = - AstFactory::create_binary_expression(counter_end_le, Operator::And, counter_start_ge, bool_id); - let and_2 = - AstFactory::create_binary_expression(counter_end_ge, Operator::And, counter_start_le, bool_id); - let or = AstFactory::create_binary_expression(and_1, Operator::Or, and_2, bool_id); - - self.register_debug_location(&or); - let or_eval = exp_gen.generate_expression(&or)?; - Ok(or_eval) - } - /// genertes a case statement /// /// CASE selector OF diff --git a/src/codegen/tests/code_gen_tests.rs b/src/codegen/tests/code_gen_tests.rs index d149b7df35..0d34a3dfd5 100644 --- a/src/codegen/tests/code_gen_tests.rs +++ b/src/codegen/tests/code_gen_tests.rs @@ -1155,6 +1155,145 @@ fn for_statement_with_references_steps_test() { insta::assert_snapshot!(result); } +#[test] +fn for_statement_with_binary_expressions() { + let result = codegen( + " + PROGRAM prg + VAR + step: DINT; + x : DINT; + y : DINT; + z : DINT; + END_VAR + FOR x := y + 1 TO z - 2 BY step * 3 DO + x; + END_FOR + END_PROGRAM + ", + ); + + insta::assert_snapshot!(result, @r###" + ; ModuleID = 'main' + source_filename = "main" + + %prg = type { i32, i32, i32, i32 } + + @prg_instance = global %prg zeroinitializer, section "var-$RUSTY$prg_instance:r4i32i32i32i32" + + define void @prg(%prg* %0) section "fn-$RUSTY$prg:v" { + entry: + %step = getelementptr inbounds %prg, %prg* %0, i32 0, i32 0 + %x = getelementptr inbounds %prg, %prg* %0, i32 0, i32 1 + %y = getelementptr inbounds %prg, %prg* %0, i32 0, i32 2 + %z = getelementptr inbounds %prg, %prg* %0, i32 0, i32 3 + %load_y = load i32, i32* %y, align 4 + %tmpVar = add i32 %load_y, 1 + store i32 %tmpVar, i32* %x, align 4 + %load_step = load i32, i32* %step, align 4 + %tmpVar1 = mul i32 %load_step, 3 + %is_incrementing = icmp sgt i32 %tmpVar1, 0 + br i1 %is_incrementing, label %predicate_sle, label %predicate_sge + + predicate_sle: ; preds = %increment, %entry + %load_z = load i32, i32* %z, align 4 + %tmpVar2 = sub i32 %load_z, 2 + %1 = load i32, i32* %x, align 4 + %condition = icmp sle i32 %1, %tmpVar2 + br i1 %condition, label %loop, label %continue + + predicate_sge: ; preds = %increment, %entry + %load_z3 = load i32, i32* %z, align 4 + %tmpVar4 = sub i32 %load_z3, 2 + %2 = load i32, i32* %x, align 4 + %condition5 = icmp sge i32 %2, %tmpVar4 + br i1 %condition5, label %loop, label %continue + + loop: ; preds = %predicate_sge, %predicate_sle + %load_x = load i32, i32* %x, align 4 + br label %increment + + increment: ; preds = %loop + %3 = load i32, i32* %x, align 4 + %load_step6 = load i32, i32* %step, align 4 + %tmpVar7 = mul i32 %load_step6, 3 + %next = add i32 %tmpVar7, %3 + store i32 %next, i32* %x, align 4 + br i1 %is_incrementing, label %predicate_sle, label %predicate_sge + + continue: ; preds = %predicate_sge, %predicate_sle + ret void + } + "###); +} + +#[test] +fn for_statement_type_casting() { + let result = codegen( + "FUNCTION main + VAR + a: USINT; + b: INT := 1; + END_VAR + FOR a := 0 TO 10 BY b DO + b := b * 3; + END_FOR + END_FUNCTION", + ); + insta::assert_snapshot!(result, @r###" + ; ModuleID = 'main' + source_filename = "main" + + define void @main() section "fn-$RUSTY$main:v" { + entry: + %a = alloca i8, align 1 + %b = alloca i16, align 2 + store i8 0, i8* %a, align 1 + store i16 1, i16* %b, align 2 + store i8 0, i8* %a, align 1 + %load_b = load i16, i16* %b, align 2 + %0 = trunc i16 %load_b to i8 + %1 = sext i8 %0 to i32 + %is_incrementing = icmp sgt i32 %1, 0 + br i1 %is_incrementing, label %predicate_sle, label %predicate_sge + + predicate_sle: ; preds = %increment, %entry + %2 = load i8, i8* %a, align 1 + %3 = zext i8 %2 to i32 + %condition = icmp sle i32 %3, 10 + br i1 %condition, label %loop, label %continue + + predicate_sge: ; preds = %increment, %entry + %4 = load i8, i8* %a, align 1 + %5 = zext i8 %4 to i32 + %condition1 = icmp sge i32 %5, 10 + br i1 %condition1, label %loop, label %continue + + loop: ; preds = %predicate_sge, %predicate_sle + %load_b2 = load i16, i16* %b, align 2 + %6 = sext i16 %load_b2 to i32 + %tmpVar = mul i32 %6, 3 + %7 = trunc i32 %tmpVar to i16 + store i16 %7, i16* %b, align 2 + br label %increment + + increment: ; preds = %loop + %8 = load i8, i8* %a, align 1 + %load_b3 = load i16, i16* %b, align 2 + %9 = trunc i16 %load_b3 to i8 + %10 = sext i8 %9 to i32 + %11 = zext i8 %8 to i32 + %next = add i32 %10, %11 + %12 = trunc i32 %next to i8 + store i8 %12, i8* %a, align 1 + br i1 %is_incrementing, label %predicate_sle, label %predicate_sge + + continue: ; preds = %predicate_sge, %predicate_sle + ret void + } + "###); +} + #[test] fn while_statement() { let result = codegen( diff --git a/src/codegen/tests/debug_tests/snapshots/rusty__codegen__tests__debug_tests__expression_debugging__for_conditions_location_marked.snap b/src/codegen/tests/debug_tests/snapshots/rusty__codegen__tests__debug_tests__expression_debugging__for_conditions_location_marked.snap index 113f95b2ce..6e12617d29 100644 --- a/src/codegen/tests/debug_tests/snapshots/rusty__codegen__tests__debug_tests__expression_debugging__for_conditions_location_marked.snap +++ b/src/codegen/tests/debug_tests/snapshots/rusty__codegen__tests__debug_tests__expression_debugging__for_conditions_location_marked.snap @@ -11,67 +11,31 @@ entry: call void @llvm.dbg.declare(metadata i32* %myFunc, metadata !9, metadata !DIExpression()), !dbg !11 store i32 0, i32* %myFunc, align 4, !dbg !8 store i32 1, i32* %myFunc, align 4, !dbg !12 - br label %condition_check, !dbg !12 + br i1 true, label %predicate_sle, label %predicate_sge, !dbg !12 -condition_check: ; preds = %increment, %entry - %load_myFunc = load i32, i32* %myFunc, align 4, !dbg !12 - %load_myFunc1 = load i32, i32* %myFunc, align 4, !dbg !12 - %tmpVar = icmp sle i32 %load_myFunc1, 20, !dbg !12 - %0 = zext i1 %tmpVar to i8, !dbg !12 - %1 = icmp ne i8 %0, 0, !dbg !12 - br i1 %1, label %2, label %5, !dbg !12 +predicate_sle: ; preds = %increment, %entry + %0 = load i32, i32* %myFunc, align 4, !dbg !12 + %condition = icmp sle i32 %0, 20, !dbg !12 + br i1 %condition, label %loop, label %continue, !dbg !12 -for_body: ; preds = %12 +predicate_sge: ; preds = %increment, %entry + %1 = load i32, i32* %myFunc, align 4, !dbg !12 + %condition1 = icmp sge i32 %1, 20, !dbg !12 + br i1 %condition1, label %loop, label %continue, !dbg !12 + +loop: ; preds = %predicate_sge, %predicate_sle store i32 1, i32* %myFunc, align 4, !dbg !13 br label %increment, !dbg !13 -increment: ; preds = %for_body - %tmpVar8 = add i32 %load_myFunc, 2, !dbg !14 - store i32 %tmpVar8, i32* %myFunc, align 4, !dbg !14 - br label %condition_check, !dbg !14 - -continue: ; preds = %12 - %myFunc_ret = load i32, i32* %myFunc, align 4, !dbg !14 - ret i32 %myFunc_ret, !dbg !14 - -2: ; preds = %condition_check - %load_myFunc2 = load i32, i32* %myFunc, align 4, !dbg !12 - %tmpVar3 = icmp sge i32 %load_myFunc2, 1, !dbg !12 - %3 = zext i1 %tmpVar3 to i8, !dbg !12 - %4 = icmp ne i8 %3, 0, !dbg !12 - br label %5, !dbg !12 - -5: ; preds = %2, %condition_check - %6 = phi i1 [ %1, %condition_check ], [ %4, %2 ], !dbg !12 - %7 = zext i1 %6 to i8, !dbg !12 - %8 = icmp ne i8 %7, 0, !dbg !12 - br i1 %8, label %12, label %9, !dbg !12 - -9: ; preds = %5 - %load_myFunc4 = load i32, i32* %myFunc, align 4, !dbg !12 - %tmpVar5 = icmp sge i32 %load_myFunc4, 20, !dbg !12 - %10 = zext i1 %tmpVar5 to i8, !dbg !12 - %11 = icmp ne i8 %10, 0, !dbg !12 - br i1 %11, label %16, label %19, !dbg !12 - -12: ; preds = %19, %5 - %13 = phi i1 [ %8, %5 ], [ %22, %19 ], !dbg !12 - %14 = zext i1 %13 to i8, !dbg !12 - %15 = icmp ne i8 %14, 0, !dbg !12 - br i1 %15, label %for_body, label %continue, !dbg !12 - -16: ; preds = %9 - %load_myFunc6 = load i32, i32* %myFunc, align 4, !dbg !12 - %tmpVar7 = icmp sle i32 %load_myFunc6, 1, !dbg !12 - %17 = zext i1 %tmpVar7 to i8, !dbg !12 - %18 = icmp ne i8 %17, 0, !dbg !12 - br label %19, !dbg !12 +increment: ; preds = %loop + %2 = load i32, i32* %myFunc, align 4, !dbg !13 + %next = add i32 2, %2, !dbg !13 + store i32 %next, i32* %myFunc, align 4, !dbg !13 + br i1 true, label %predicate_sle, label %predicate_sge, !dbg !13 -19: ; preds = %16, %9 - %20 = phi i1 [ %11, %9 ], [ %18, %16 ], !dbg !12 - %21 = zext i1 %20 to i8, !dbg !12 - %22 = icmp ne i8 %21, 0, !dbg !12 - br label %12, !dbg !12 +continue: ; preds = %predicate_sge, %predicate_sle + %myFunc_ret = load i32, i32* %myFunc, align 4, !dbg !13 + ret i32 %myFunc_ret, !dbg !13 } ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn @@ -96,4 +60,3 @@ attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } !11 = !DILocation(line: 2, column: 17, scope: !4) !12 = !DILocation(line: 3, column: 16, scope: !4) !13 = !DILocation(line: 4, column: 16, scope: !4) -!14 = !DILocation(line: 3, column: 37, scope: !4) diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_continue.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_continue.snap index 9f41468169..ccff95cd6e 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_continue.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_continue.snap @@ -13,64 +13,28 @@ define void @prg(%prg* %0) section "fn-$RUSTY$prg:v" { entry: %x = getelementptr inbounds %prg, %prg* %0, i32 0, i32 0 store i32 3, i32* %x, align 4 - br label %condition_check + br i1 true, label %predicate_sle, label %predicate_sge -condition_check: ; preds = %increment, %entry - %load_x = load i32, i32* %x, align 4 - %load_x1 = load i32, i32* %x, align 4 - %tmpVar = icmp sle i32 %load_x1, 10 - %1 = zext i1 %tmpVar to i8 - %2 = icmp ne i8 %1, 0 - br i1 %2, label %3, label %6 +predicate_sle: ; preds = %increment, %entry + %1 = load i32, i32* %x, align 4 + %condition = icmp sle i32 %1, 10 + br i1 %condition, label %loop, label %continue + +predicate_sge: ; preds = %increment, %entry + %2 = load i32, i32* %x, align 4 + %condition1 = icmp sge i32 %2, 10 + br i1 %condition1, label %loop, label %continue -for_body: ; preds = %13 +loop: ; preds = %predicate_sge, %predicate_sle br label %increment -increment: ; preds = %for_body - %tmpVar8 = add i32 %load_x, 1 - store i32 %tmpVar8, i32* %x, align 4 - br label %condition_check +increment: ; preds = %loop + %3 = load i32, i32* %x, align 4 + %next = add i32 1, %3 + store i32 %next, i32* %x, align 4 + br i1 true, label %predicate_sle, label %predicate_sge -continue: ; preds = %13 - %load_x9 = load i32, i32* %x, align 4 +continue: ; preds = %predicate_sge, %predicate_sle + %load_x = load i32, i32* %x, align 4 ret void - -3: ; preds = %condition_check - %load_x2 = load i32, i32* %x, align 4 - %tmpVar3 = icmp sge i32 %load_x2, 3 - %4 = zext i1 %tmpVar3 to i8 - %5 = icmp ne i8 %4, 0 - br label %6 - -6: ; preds = %3, %condition_check - %7 = phi i1 [ %2, %condition_check ], [ %5, %3 ] - %8 = zext i1 %7 to i8 - %9 = icmp ne i8 %8, 0 - br i1 %9, label %13, label %10 - -10: ; preds = %6 - %load_x4 = load i32, i32* %x, align 4 - %tmpVar5 = icmp sge i32 %load_x4, 10 - %11 = zext i1 %tmpVar5 to i8 - %12 = icmp ne i8 %11, 0 - br i1 %12, label %17, label %20 - -13: ; preds = %20, %6 - %14 = phi i1 [ %9, %6 ], [ %23, %20 ] - %15 = zext i1 %14 to i8 - %16 = icmp ne i8 %15, 0 - br i1 %16, label %for_body, label %continue - -17: ; preds = %10 - %load_x6 = load i32, i32* %x, align 4 - %tmpVar7 = icmp sle i32 %load_x6, 3 - %18 = zext i1 %tmpVar7 to i8 - %19 = icmp ne i8 %18, 0 - br label %20 - -20: ; preds = %17, %10 - %21 = phi i1 [ %12, %10 ], [ %19, %17 ] - %22 = zext i1 %21 to i8 - %23 = icmp ne i8 %22, 0 - br label %13 } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_int.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_int.snap index 2dca83f31a..58c3bc0e70 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_int.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_int.snap @@ -13,64 +13,32 @@ define void @prg(%prg* %0) section "fn-$RUSTY$prg:v" { entry: %x = getelementptr inbounds %prg, %prg* %0, i32 0, i32 0 store i16 3, i16* %x, align 2 - br label %condition_check + br i1 true, label %predicate_sle, label %predicate_sge -condition_check: ; preds = %increment, %entry - %load_x = load i16, i16* %x, align 2 - %load_x1 = load i16, i16* %x, align 2 - %tmpVar = icmp sle i16 %load_x1, 10 - %1 = zext i1 %tmpVar to i8 - %2 = icmp ne i8 %1, 0 - br i1 %2, label %3, label %6 +predicate_sle: ; preds = %increment, %entry + %1 = load i16, i16* %x, align 2 + %2 = sext i16 %1 to i32 + %condition = icmp sle i32 %2, 10 + br i1 %condition, label %loop, label %continue + +predicate_sge: ; preds = %increment, %entry + %3 = load i16, i16* %x, align 2 + %4 = sext i16 %3 to i32 + %condition1 = icmp sge i32 %4, 10 + br i1 %condition1, label %loop, label %continue -for_body: ; preds = %13 - %load_x8 = load i16, i16* %x, align 2 +loop: ; preds = %predicate_sge, %predicate_sle + %load_x = load i16, i16* %x, align 2 br label %increment -increment: ; preds = %for_body - %tmpVar9 = add i16 %load_x, 1 - store i16 %tmpVar9, i16* %x, align 2 - br label %condition_check +increment: ; preds = %loop + %5 = load i16, i16* %x, align 2 + %6 = sext i16 %5 to i32 + %next = add i32 1, %6 + %7 = trunc i32 %next to i16 + store i16 %7, i16* %x, align 2 + br i1 true, label %predicate_sle, label %predicate_sge -continue: ; preds = %13 +continue: ; preds = %predicate_sge, %predicate_sle ret void - -3: ; preds = %condition_check - %load_x2 = load i16, i16* %x, align 2 - %tmpVar3 = icmp sge i16 %load_x2, 3 - %4 = zext i1 %tmpVar3 to i8 - %5 = icmp ne i8 %4, 0 - br label %6 - -6: ; preds = %3, %condition_check - %7 = phi i1 [ %2, %condition_check ], [ %5, %3 ] - %8 = zext i1 %7 to i8 - %9 = icmp ne i8 %8, 0 - br i1 %9, label %13, label %10 - -10: ; preds = %6 - %load_x4 = load i16, i16* %x, align 2 - %tmpVar5 = icmp sge i16 %load_x4, 10 - %11 = zext i1 %tmpVar5 to i8 - %12 = icmp ne i8 %11, 0 - br i1 %12, label %17, label %20 - -13: ; preds = %20, %6 - %14 = phi i1 [ %9, %6 ], [ %23, %20 ] - %15 = zext i1 %14 to i8 - %16 = icmp ne i8 %15, 0 - br i1 %16, label %for_body, label %continue - -17: ; preds = %10 - %load_x6 = load i16, i16* %x, align 2 - %tmpVar7 = icmp sle i16 %load_x6, 3 - %18 = zext i1 %tmpVar7 to i8 - %19 = icmp ne i8 %18, 0 - br label %20 - -20: ; preds = %17, %10 - %21 = phi i1 [ %12, %10 ], [ %19, %17 ] - %22 = zext i1 %21 to i8 - %23 = icmp ne i8 %22, 0 - br label %13 } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_lint.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_lint.snap index 0310b77ae1..f0ba938547 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_lint.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_lint.snap @@ -13,64 +13,28 @@ define void @prg(%prg* %0) section "fn-$RUSTY$prg:v" { entry: %x = getelementptr inbounds %prg, %prg* %0, i32 0, i32 0 store i64 3, i64* %x, align 4 - br label %condition_check + br i1 true, label %predicate_sle, label %predicate_sge -condition_check: ; preds = %increment, %entry - %load_x = load i64, i64* %x, align 4 - %load_x1 = load i64, i64* %x, align 4 - %tmpVar = icmp sle i64 %load_x1, 10 - %1 = zext i1 %tmpVar to i8 - %2 = icmp ne i8 %1, 0 - br i1 %2, label %3, label %6 +predicate_sle: ; preds = %increment, %entry + %1 = load i64, i64* %x, align 4 + %condition = icmp sle i64 %1, 10 + br i1 %condition, label %loop, label %continue + +predicate_sge: ; preds = %increment, %entry + %2 = load i64, i64* %x, align 4 + %condition1 = icmp sge i64 %2, 10 + br i1 %condition1, label %loop, label %continue -for_body: ; preds = %13 - %load_x8 = load i64, i64* %x, align 4 +loop: ; preds = %predicate_sge, %predicate_sle + %load_x = load i64, i64* %x, align 4 br label %increment -increment: ; preds = %for_body - %tmpVar9 = add i64 %load_x, 1 - store i64 %tmpVar9, i64* %x, align 4 - br label %condition_check +increment: ; preds = %loop + %3 = load i64, i64* %x, align 4 + %next = add i64 1, %3 + store i64 %next, i64* %x, align 4 + br i1 true, label %predicate_sle, label %predicate_sge -continue: ; preds = %13 +continue: ; preds = %predicate_sge, %predicate_sle ret void - -3: ; preds = %condition_check - %load_x2 = load i64, i64* %x, align 4 - %tmpVar3 = icmp sge i64 %load_x2, 3 - %4 = zext i1 %tmpVar3 to i8 - %5 = icmp ne i8 %4, 0 - br label %6 - -6: ; preds = %3, %condition_check - %7 = phi i1 [ %2, %condition_check ], [ %5, %3 ] - %8 = zext i1 %7 to i8 - %9 = icmp ne i8 %8, 0 - br i1 %9, label %13, label %10 - -10: ; preds = %6 - %load_x4 = load i64, i64* %x, align 4 - %tmpVar5 = icmp sge i64 %load_x4, 10 - %11 = zext i1 %tmpVar5 to i8 - %12 = icmp ne i8 %11, 0 - br i1 %12, label %17, label %20 - -13: ; preds = %20, %6 - %14 = phi i1 [ %9, %6 ], [ %23, %20 ] - %15 = zext i1 %14 to i8 - %16 = icmp ne i8 %15, 0 - br i1 %16, label %for_body, label %continue - -17: ; preds = %10 - %load_x6 = load i64, i64* %x, align 4 - %tmpVar7 = icmp sle i64 %load_x6, 3 - %18 = zext i1 %tmpVar7 to i8 - %19 = icmp ne i8 %18, 0 - br label %20 - -20: ; preds = %17, %10 - %21 = phi i1 [ %12, %10 ], [ %19, %17 ] - %22 = zext i1 %21 to i8 - %23 = icmp ne i8 %22, 0 - br label %13 } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_sint.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_sint.snap index 9d83bc8b7d..939f4cbb48 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_sint.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_sint.snap @@ -13,64 +13,32 @@ define void @prg(%prg* %0) section "fn-$RUSTY$prg:v" { entry: %x = getelementptr inbounds %prg, %prg* %0, i32 0, i32 0 store i8 3, i8* %x, align 1 - br label %condition_check + br i1 true, label %predicate_sle, label %predicate_sge -condition_check: ; preds = %increment, %entry - %load_x = load i8, i8* %x, align 1 - %load_x1 = load i8, i8* %x, align 1 - %tmpVar = icmp sle i8 %load_x1, 10 - %1 = zext i1 %tmpVar to i8 - %2 = icmp ne i8 %1, 0 - br i1 %2, label %3, label %6 +predicate_sle: ; preds = %increment, %entry + %1 = load i8, i8* %x, align 1 + %2 = sext i8 %1 to i32 + %condition = icmp sle i32 %2, 10 + br i1 %condition, label %loop, label %continue + +predicate_sge: ; preds = %increment, %entry + %3 = load i8, i8* %x, align 1 + %4 = sext i8 %3 to i32 + %condition1 = icmp sge i32 %4, 10 + br i1 %condition1, label %loop, label %continue -for_body: ; preds = %13 - %load_x8 = load i8, i8* %x, align 1 +loop: ; preds = %predicate_sge, %predicate_sle + %load_x = load i8, i8* %x, align 1 br label %increment -increment: ; preds = %for_body - %tmpVar9 = add i8 %load_x, 1 - store i8 %tmpVar9, i8* %x, align 1 - br label %condition_check +increment: ; preds = %loop + %5 = load i8, i8* %x, align 1 + %6 = sext i8 %5 to i32 + %next = add i32 1, %6 + %7 = trunc i32 %next to i8 + store i8 %7, i8* %x, align 1 + br i1 true, label %predicate_sle, label %predicate_sge -continue: ; preds = %13 +continue: ; preds = %predicate_sge, %predicate_sle ret void - -3: ; preds = %condition_check - %load_x2 = load i8, i8* %x, align 1 - %tmpVar3 = icmp sge i8 %load_x2, 3 - %4 = zext i1 %tmpVar3 to i8 - %5 = icmp ne i8 %4, 0 - br label %6 - -6: ; preds = %3, %condition_check - %7 = phi i1 [ %2, %condition_check ], [ %5, %3 ] - %8 = zext i1 %7 to i8 - %9 = icmp ne i8 %8, 0 - br i1 %9, label %13, label %10 - -10: ; preds = %6 - %load_x4 = load i8, i8* %x, align 1 - %tmpVar5 = icmp sge i8 %load_x4, 10 - %11 = zext i1 %tmpVar5 to i8 - %12 = icmp ne i8 %11, 0 - br i1 %12, label %17, label %20 - -13: ; preds = %20, %6 - %14 = phi i1 [ %9, %6 ], [ %23, %20 ] - %15 = zext i1 %14 to i8 - %16 = icmp ne i8 %15, 0 - br i1 %16, label %for_body, label %continue - -17: ; preds = %10 - %load_x6 = load i8, i8* %x, align 1 - %tmpVar7 = icmp sle i8 %load_x6, 3 - %18 = zext i1 %tmpVar7 to i8 - %19 = icmp ne i8 %18, 0 - br label %20 - -20: ; preds = %17, %10 - %21 = phi i1 [ %12, %10 ], [ %19, %17 ] - %22 = zext i1 %21 to i8 - %23 = icmp ne i8 %22, 0 - br label %13 } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_continue.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_continue.snap index 08569854f0..d8dcfd34db 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_continue.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_continue.snap @@ -13,72 +13,36 @@ define void @prg(%prg* %0) section "fn-$RUSTY$prg:v" { entry: %x = getelementptr inbounds %prg, %prg* %0, i32 0, i32 0 store i32 3, i32* %x, align 4 - br label %condition_check + br i1 true, label %predicate_sle, label %predicate_sge -condition_check: ; preds = %increment, %entry - %load_x = load i32, i32* %x, align 4 - %load_x1 = load i32, i32* %x, align 4 - %tmpVar = icmp sle i32 %load_x1, 10 - %1 = zext i1 %tmpVar to i8 - %2 = icmp ne i8 %1, 0 - br i1 %2, label %3, label %6 +predicate_sle: ; preds = %increment, %entry + %1 = load i32, i32* %x, align 4 + %condition = icmp sle i32 %1, 10 + br i1 %condition, label %loop, label %continue + +predicate_sge: ; preds = %increment, %entry + %2 = load i32, i32* %x, align 4 + %condition1 = icmp sge i32 %2, 10 + br i1 %condition1, label %loop, label %continue -for_body: ; preds = %13 - %load_x8 = load i32, i32* %x, align 4 - %tmpVar9 = add i32 %load_x8, 1 - store i32 %tmpVar9, i32* %x, align 4 +loop: ; preds = %predicate_sge, %predicate_sle + %load_x = load i32, i32* %x, align 4 + %tmpVar = add i32 %load_x, 1 + store i32 %tmpVar, i32* %x, align 4 br label %increment buffer_block: ; No predecessors! - %load_x10 = load i32, i32* %x, align 4 - %tmpVar11 = sub i32 %load_x10, 1 - store i32 %tmpVar11, i32* %x, align 4 + %load_x2 = load i32, i32* %x, align 4 + %tmpVar3 = sub i32 %load_x2, 1 + store i32 %tmpVar3, i32* %x, align 4 br label %increment -increment: ; preds = %buffer_block, %for_body - %tmpVar12 = add i32 %load_x, 7 - store i32 %tmpVar12, i32* %x, align 4 - br label %condition_check +increment: ; preds = %buffer_block, %loop + %3 = load i32, i32* %x, align 4 + %next = add i32 7, %3 + store i32 %next, i32* %x, align 4 + br i1 true, label %predicate_sle, label %predicate_sge -continue: ; preds = %13 +continue: ; preds = %predicate_sge, %predicate_sle ret void - -3: ; preds = %condition_check - %load_x2 = load i32, i32* %x, align 4 - %tmpVar3 = icmp sge i32 %load_x2, 3 - %4 = zext i1 %tmpVar3 to i8 - %5 = icmp ne i8 %4, 0 - br label %6 - -6: ; preds = %3, %condition_check - %7 = phi i1 [ %2, %condition_check ], [ %5, %3 ] - %8 = zext i1 %7 to i8 - %9 = icmp ne i8 %8, 0 - br i1 %9, label %13, label %10 - -10: ; preds = %6 - %load_x4 = load i32, i32* %x, align 4 - %tmpVar5 = icmp sge i32 %load_x4, 10 - %11 = zext i1 %tmpVar5 to i8 - %12 = icmp ne i8 %11, 0 - br i1 %12, label %17, label %20 - -13: ; preds = %20, %6 - %14 = phi i1 [ %9, %6 ], [ %23, %20 ] - %15 = zext i1 %14 to i8 - %16 = icmp ne i8 %15, 0 - br i1 %16, label %for_body, label %continue - -17: ; preds = %10 - %load_x6 = load i32, i32* %x, align 4 - %tmpVar7 = icmp sle i32 %load_x6, 3 - %18 = zext i1 %tmpVar7 to i8 - %19 = icmp ne i8 %18, 0 - br label %20 - -20: ; preds = %17, %10 - %21 = phi i1 [ %12, %10 ], [ %19, %17 ] - %22 = zext i1 %21 to i8 - %23 = icmp ne i8 %22, 0 - br label %13 } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_exit.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_exit.snap index 1a9a034b13..00a9396ea4 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_exit.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_exit.snap @@ -13,72 +13,36 @@ define void @prg(%prg* %0) section "fn-$RUSTY$prg:v" { entry: %x = getelementptr inbounds %prg, %prg* %0, i32 0, i32 0 store i32 3, i32* %x, align 4 - br label %condition_check + br i1 true, label %predicate_sle, label %predicate_sge -condition_check: ; preds = %increment, %entry - %load_x = load i32, i32* %x, align 4 - %load_x1 = load i32, i32* %x, align 4 - %tmpVar = icmp sle i32 %load_x1, 10 - %1 = zext i1 %tmpVar to i8 - %2 = icmp ne i8 %1, 0 - br i1 %2, label %3, label %6 +predicate_sle: ; preds = %increment, %entry + %1 = load i32, i32* %x, align 4 + %condition = icmp sle i32 %1, 10 + br i1 %condition, label %loop, label %continue + +predicate_sge: ; preds = %increment, %entry + %2 = load i32, i32* %x, align 4 + %condition1 = icmp sge i32 %2, 10 + br i1 %condition1, label %loop, label %continue -for_body: ; preds = %13 - %load_x8 = load i32, i32* %x, align 4 - %tmpVar9 = add i32 %load_x8, 2 - store i32 %tmpVar9, i32* %x, align 4 +loop: ; preds = %predicate_sge, %predicate_sle + %load_x = load i32, i32* %x, align 4 + %tmpVar = add i32 %load_x, 2 + store i32 %tmpVar, i32* %x, align 4 br label %continue buffer_block: ; No predecessors! - %load_x10 = load i32, i32* %x, align 4 - %tmpVar11 = add i32 %load_x10, 5 - store i32 %tmpVar11, i32* %x, align 4 + %load_x2 = load i32, i32* %x, align 4 + %tmpVar3 = add i32 %load_x2, 5 + store i32 %tmpVar3, i32* %x, align 4 br label %increment increment: ; preds = %buffer_block - %tmpVar12 = add i32 %load_x, 7 - store i32 %tmpVar12, i32* %x, align 4 - br label %condition_check + %3 = load i32, i32* %x, align 4 + %next = add i32 7, %3 + store i32 %next, i32* %x, align 4 + br i1 true, label %predicate_sle, label %predicate_sge -continue: ; preds = %for_body, %13 +continue: ; preds = %loop, %predicate_sge, %predicate_sle ret void - -3: ; preds = %condition_check - %load_x2 = load i32, i32* %x, align 4 - %tmpVar3 = icmp sge i32 %load_x2, 3 - %4 = zext i1 %tmpVar3 to i8 - %5 = icmp ne i8 %4, 0 - br label %6 - -6: ; preds = %3, %condition_check - %7 = phi i1 [ %2, %condition_check ], [ %5, %3 ] - %8 = zext i1 %7 to i8 - %9 = icmp ne i8 %8, 0 - br i1 %9, label %13, label %10 - -10: ; preds = %6 - %load_x4 = load i32, i32* %x, align 4 - %tmpVar5 = icmp sge i32 %load_x4, 10 - %11 = zext i1 %tmpVar5 to i8 - %12 = icmp ne i8 %11, 0 - br i1 %12, label %17, label %20 - -13: ; preds = %20, %6 - %14 = phi i1 [ %9, %6 ], [ %23, %20 ] - %15 = zext i1 %14 to i8 - %16 = icmp ne i8 %15, 0 - br i1 %16, label %for_body, label %continue - -17: ; preds = %10 - %load_x6 = load i32, i32* %x, align 4 - %tmpVar7 = icmp sle i32 %load_x6, 3 - %18 = zext i1 %tmpVar7 to i8 - %19 = icmp ne i8 %18, 0 - br label %20 - -20: ; preds = %17, %10 - %21 = phi i1 [ %12, %10 ], [ %19, %17 ] - %22 = zext i1 %21 to i8 - %23 = icmp ne i8 %22, 0 - br label %13 } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_references_steps_test.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_references_steps_test.snap index a3881483a7..28d0351a43 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_references_steps_test.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_references_steps_test.snap @@ -17,69 +17,33 @@ entry: %z = getelementptr inbounds %prg, %prg* %0, i32 0, i32 3 %load_y = load i32, i32* %y, align 4 store i32 %load_y, i32* %x, align 4 - br label %condition_check - -condition_check: ; preds = %increment, %entry + %load_step = load i32, i32* %step, align 4 + %is_incrementing = icmp sgt i32 %load_step, 0 + br i1 %is_incrementing, label %predicate_sle, label %predicate_sge + +predicate_sle: ; preds = %increment, %entry + %1 = load i32, i32* %z, align 4 + %2 = load i32, i32* %x, align 4 + %condition = icmp sle i32 %2, %1 + br i1 %condition, label %loop, label %continue + +predicate_sge: ; preds = %increment, %entry + %3 = load i32, i32* %z, align 4 + %4 = load i32, i32* %x, align 4 + %condition1 = icmp sge i32 %4, %3 + br i1 %condition1, label %loop, label %continue + +loop: ; preds = %predicate_sge, %predicate_sle %load_x = load i32, i32* %x, align 4 - %load_x1 = load i32, i32* %x, align 4 - %load_z = load i32, i32* %z, align 4 - %tmpVar = icmp sle i32 %load_x1, %load_z - %1 = zext i1 %tmpVar to i8 - %2 = icmp ne i8 %1, 0 - br i1 %2, label %3, label %6 - -for_body: ; preds = %13 - %load_x11 = load i32, i32* %x, align 4 br label %increment -increment: ; preds = %for_body - %load_step = load i32, i32* %step, align 4 - %tmpVar12 = add i32 %load_x, %load_step - store i32 %tmpVar12, i32* %x, align 4 - br label %condition_check +increment: ; preds = %loop + %5 = load i32, i32* %x, align 4 + %load_step2 = load i32, i32* %step, align 4 + %next = add i32 %load_step2, %5 + store i32 %next, i32* %x, align 4 + br i1 %is_incrementing, label %predicate_sle, label %predicate_sge -continue: ; preds = %13 +continue: ; preds = %predicate_sge, %predicate_sle ret void - -3: ; preds = %condition_check - %load_x2 = load i32, i32* %x, align 4 - %load_y3 = load i32, i32* %y, align 4 - %tmpVar4 = icmp sge i32 %load_x2, %load_y3 - %4 = zext i1 %tmpVar4 to i8 - %5 = icmp ne i8 %4, 0 - br label %6 - -6: ; preds = %3, %condition_check - %7 = phi i1 [ %2, %condition_check ], [ %5, %3 ] - %8 = zext i1 %7 to i8 - %9 = icmp ne i8 %8, 0 - br i1 %9, label %13, label %10 - -10: ; preds = %6 - %load_x5 = load i32, i32* %x, align 4 - %load_z6 = load i32, i32* %z, align 4 - %tmpVar7 = icmp sge i32 %load_x5, %load_z6 - %11 = zext i1 %tmpVar7 to i8 - %12 = icmp ne i8 %11, 0 - br i1 %12, label %17, label %20 - -13: ; preds = %20, %6 - %14 = phi i1 [ %9, %6 ], [ %23, %20 ] - %15 = zext i1 %14 to i8 - %16 = icmp ne i8 %15, 0 - br i1 %16, label %for_body, label %continue - -17: ; preds = %10 - %load_x8 = load i32, i32* %x, align 4 - %load_y9 = load i32, i32* %y, align 4 - %tmpVar10 = icmp sle i32 %load_x8, %load_y9 - %18 = zext i1 %tmpVar10 to i8 - %19 = icmp ne i8 %18, 0 - br label %20 - -20: ; preds = %17, %10 - %21 = phi i1 [ %12, %10 ], [ %19, %17 ] - %22 = zext i1 %21 to i8 - %23 = icmp ne i8 %22, 0 - br label %13 } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_steps_test.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_steps_test.snap index f0bb8cb4e5..d32995dea1 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_steps_test.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_with_steps_test.snap @@ -13,64 +13,28 @@ define void @prg(%prg* %0) section "fn-$RUSTY$prg:v" { entry: %x = getelementptr inbounds %prg, %prg* %0, i32 0, i32 0 store i32 3, i32* %x, align 4 - br label %condition_check + br i1 true, label %predicate_sle, label %predicate_sge -condition_check: ; preds = %increment, %entry - %load_x = load i32, i32* %x, align 4 - %load_x1 = load i32, i32* %x, align 4 - %tmpVar = icmp sle i32 %load_x1, 10 - %1 = zext i1 %tmpVar to i8 - %2 = icmp ne i8 %1, 0 - br i1 %2, label %3, label %6 +predicate_sle: ; preds = %increment, %entry + %1 = load i32, i32* %x, align 4 + %condition = icmp sle i32 %1, 10 + br i1 %condition, label %loop, label %continue + +predicate_sge: ; preds = %increment, %entry + %2 = load i32, i32* %x, align 4 + %condition1 = icmp sge i32 %2, 10 + br i1 %condition1, label %loop, label %continue -for_body: ; preds = %13 - %load_x8 = load i32, i32* %x, align 4 +loop: ; preds = %predicate_sge, %predicate_sle + %load_x = load i32, i32* %x, align 4 br label %increment -increment: ; preds = %for_body - %tmpVar9 = add i32 %load_x, 7 - store i32 %tmpVar9, i32* %x, align 4 - br label %condition_check +increment: ; preds = %loop + %3 = load i32, i32* %x, align 4 + %next = add i32 7, %3 + store i32 %next, i32* %x, align 4 + br i1 true, label %predicate_sle, label %predicate_sge -continue: ; preds = %13 +continue: ; preds = %predicate_sge, %predicate_sle ret void - -3: ; preds = %condition_check - %load_x2 = load i32, i32* %x, align 4 - %tmpVar3 = icmp sge i32 %load_x2, 3 - %4 = zext i1 %tmpVar3 to i8 - %5 = icmp ne i8 %4, 0 - br label %6 - -6: ; preds = %3, %condition_check - %7 = phi i1 [ %2, %condition_check ], [ %5, %3 ] - %8 = zext i1 %7 to i8 - %9 = icmp ne i8 %8, 0 - br i1 %9, label %13, label %10 - -10: ; preds = %6 - %load_x4 = load i32, i32* %x, align 4 - %tmpVar5 = icmp sge i32 %load_x4, 10 - %11 = zext i1 %tmpVar5 to i8 - %12 = icmp ne i8 %11, 0 - br i1 %12, label %17, label %20 - -13: ; preds = %20, %6 - %14 = phi i1 [ %9, %6 ], [ %23, %20 ] - %15 = zext i1 %14 to i8 - %16 = icmp ne i8 %15, 0 - br i1 %16, label %for_body, label %continue - -17: ; preds = %10 - %load_x6 = load i32, i32* %x, align 4 - %tmpVar7 = icmp sle i32 %load_x6, 3 - %18 = zext i1 %tmpVar7 to i8 - %19 = icmp ne i8 %18, 0 - br label %20 - -20: ; preds = %17, %10 - %21 = phi i1 [ %12, %10 ], [ %19, %17 ] - %22 = zext i1 %21 to i8 - %23 = icmp ne i8 %22, 0 - br label %13 } diff --git a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_without_steps_test.snap b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_without_steps_test.snap index 6c28295463..411285a0cc 100644 --- a/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_without_steps_test.snap +++ b/src/codegen/tests/snapshots/rusty__codegen__tests__code_gen_tests__for_statement_without_steps_test.snap @@ -13,64 +13,28 @@ define void @prg(%prg* %0) section "fn-$RUSTY$prg:v" { entry: %x = getelementptr inbounds %prg, %prg* %0, i32 0, i32 0 store i32 3, i32* %x, align 4 - br label %condition_check + br i1 true, label %predicate_sle, label %predicate_sge -condition_check: ; preds = %increment, %entry - %load_x = load i32, i32* %x, align 4 - %load_x1 = load i32, i32* %x, align 4 - %tmpVar = icmp sle i32 %load_x1, 10 - %1 = zext i1 %tmpVar to i8 - %2 = icmp ne i8 %1, 0 - br i1 %2, label %3, label %6 +predicate_sle: ; preds = %increment, %entry + %1 = load i32, i32* %x, align 4 + %condition = icmp sle i32 %1, 10 + br i1 %condition, label %loop, label %continue + +predicate_sge: ; preds = %increment, %entry + %2 = load i32, i32* %x, align 4 + %condition1 = icmp sge i32 %2, 10 + br i1 %condition1, label %loop, label %continue -for_body: ; preds = %13 - %load_x8 = load i32, i32* %x, align 4 +loop: ; preds = %predicate_sge, %predicate_sle + %load_x = load i32, i32* %x, align 4 br label %increment -increment: ; preds = %for_body - %tmpVar9 = add i32 %load_x, 1 - store i32 %tmpVar9, i32* %x, align 4 - br label %condition_check +increment: ; preds = %loop + %3 = load i32, i32* %x, align 4 + %next = add i32 1, %3 + store i32 %next, i32* %x, align 4 + br i1 true, label %predicate_sle, label %predicate_sge -continue: ; preds = %13 +continue: ; preds = %predicate_sge, %predicate_sle ret void - -3: ; preds = %condition_check - %load_x2 = load i32, i32* %x, align 4 - %tmpVar3 = icmp sge i32 %load_x2, 3 - %4 = zext i1 %tmpVar3 to i8 - %5 = icmp ne i8 %4, 0 - br label %6 - -6: ; preds = %3, %condition_check - %7 = phi i1 [ %2, %condition_check ], [ %5, %3 ] - %8 = zext i1 %7 to i8 - %9 = icmp ne i8 %8, 0 - br i1 %9, label %13, label %10 - -10: ; preds = %6 - %load_x4 = load i32, i32* %x, align 4 - %tmpVar5 = icmp sge i32 %load_x4, 10 - %11 = zext i1 %tmpVar5 to i8 - %12 = icmp ne i8 %11, 0 - br i1 %12, label %17, label %20 - -13: ; preds = %20, %6 - %14 = phi i1 [ %9, %6 ], [ %23, %20 ] - %15 = zext i1 %14 to i8 - %16 = icmp ne i8 %15, 0 - br i1 %16, label %for_body, label %continue - -17: ; preds = %10 - %load_x6 = load i32, i32* %x, align 4 - %tmpVar7 = icmp sle i32 %load_x6, 3 - %18 = zext i1 %tmpVar7 to i8 - %19 = icmp ne i8 %18, 0 - br label %20 - -20: ; preds = %17, %10 - %21 = phi i1 [ %12, %10 ], [ %19, %17 ] - %22 = zext i1 %21 to i8 - %23 = icmp ne i8 %22, 0 - br label %13 } diff --git a/tests/correctness/control_flow.rs b/tests/correctness/control_flow.rs index d84495f16a..cef4a61aef 100644 --- a/tests/correctness/control_flow.rs +++ b/tests/correctness/control_flow.rs @@ -483,6 +483,109 @@ fn for_loop_and_increment_10_times_skipping_1() { assert_eq!(res, 1005); } +#[test] +fn for_loop_does_not_execute_if_condition_is_not_met() { + let function = r#" + FUNCTION main : DINT + VAR + i, end, step, res: DINT; + END_VAR + end := -1; + step := -1; + res := 100; + + FOR i := end TO 0 BY step DO + res := i; + END_FOR + + main := res; + END_FUNCTION + "#; + + let res: i32 = compile_and_run(function.to_string(), &mut crate::MainType::default()); + assert_eq!(res, 100); +} + +#[test] +fn for_loop_step_changes_sign_in_loop_body() { + let function = r#" + FUNCTION main : DINT + VAR + i, step, temp, iteration: DINT; + END_VAR + step := 1; + iteration := 0; + + FOR i := 5 TO 10 BY step DO + temp := (step + 1) * -1 ; + IF i + temp > 0 THEN + step := temp; + ELSE + step := step + 3; + END_IF; + + // i: 5, 3, 4, 2, 3, 1, 2, 6, 1, 5, 12 + // step: -2, 1, -2, 1, -2, 1, 4, -5, 4, 7 + iteration := iteration + 1; + END_FOR + + main := iteration; + END_FUNCTION + "#; + + let res: i32 = compile_and_run(function.to_string(), &mut crate::MainType::default()); + assert_eq!(res, 10); +} + +#[test] +fn for_loop_step_and_counter_change_sign_in_loop_body() { + let function = r#" + FUNCTION main : DINT + VAR + i, step, temp, iteration: DINT; + END_VAR + step := 1; + iteration := 0; + + FOR i := 3 TO 10 BY step DO + step := (step + 1) * -2; + + // i: 3, -1, 5, -9, 17 + // step: -4, 5, -14, 26 + iteration := iteration + 1; + END_FOR + + main := iteration; + END_FUNCTION + "#; + + let res: i32 = compile_and_run(function.to_string(), &mut crate::MainType::default()); + assert_eq!(res, 4); +} + +#[test] +fn for_loop_statement_with_binary_expressions() { + let function = r#" + FUNCTION main : DINT + VAR + step: DINT := 1; + x, y, iteration : DINT; + z : DINT := 25; + END_VAR + // 1 TO 23 BY 3 + FOR x := y + 1 TO z - 2 BY step * 3 DO + // x: 1, 4, 7, 10, 13, 16, 19, 22 + iteration := iteration + 1; + END_FOR + + main := iteration; + END_FUNCTION + "#; + + let res: i32 = compile_and_run(function.to_string(), &mut crate::MainType::default()); + assert_eq!(res, 8); +} + #[test] fn while_loop_no_entry() { let function = r#"