Revert "Range Analysis: Get loop exit condition from body block"
This reverts commit 1411699ba4cdf29eca037c4320543ab8189bad28.
Reason for revert: Crashing on the cmake-linux-clang-dbg-x64-ubsan bot
[ RUN ] IR_IntegerRangeAnalysisTest.AnalyzeLoopBody_Failure_Index_LessThan_Min_I32
/b/s/w/ir/cache/uncached/dawn/src/tint/lang/core/number.h:176:46: runtime error: negation of -2147483648 cannot be represented in type 'type' (aka 'int'); cast to an unsigned type to negate this value to itself
Original change's description:
> Range Analysis: Get loop exit condition from body block
>
> This patch is the third part to implement the computation of the
> range on the loop control variables. In this patch we implement the
> function `GetBinaryToCompareLoopControlVariableInLoopBody()` to get
> the condition to exit the loop in the loop body block if the loop
> meets the below requirements (a straightforward for-loop):
> - The loop control variable is only used as the parameter of the
> load instruction.
> - The first instruction is to load the loop control variable into a
> temporary variable.
> - The second instruction is to compare the temporary variable with
> a constant value and save the result to a boolean variable.
> - The second instruction cannot be a comparison that will never be
> true (out of range of 32-bit integer).
> - The third instruction is an `ifelse` expression that uses the
> boolean variable got in the second instruction as the condition.
> - The true block of the above `ifelse` expression doesn't contain
> `exit_loop`.
> - The false block of the above `ifelse` expression only contains
> `exit_loop`.
>
> Bug: chromium:348701956
> Test: tint_unittests
> Change-Id: Ie99911791eb6530e6d081ac9b54c2ec74e1be64c
> Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/233294
> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
> Reviewed-by: James Price <jrprice@google.com>
TBR=jiawei.shao@intel.com,dneto@google.com,jrprice@google.com,dawn-scoped@luci-project-accounts.iam.gserviceaccount.com
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: chromium:348701956
Change-Id: Idf151f39c2b25d66d0ce40dd31300735f3aabf76
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/234094
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Auto-Submit: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/core/ir/analysis/integer_range_analysis.cc b/src/tint/lang/core/ir/analysis/integer_range_analysis.cc
index 7ea8370..1e7384d 100644
--- a/src/tint/lang/core/ir/analysis/integer_range_analysis.cc
+++ b/src/tint/lang/core/ir/analysis/integer_range_analysis.cc
@@ -31,10 +31,7 @@
#include "src/tint/lang/core/constant/scalar.h"
#include "src/tint/lang/core/ir/binary.h"
-#include "src/tint/lang/core/ir/exit_if.h"
-#include "src/tint/lang/core/ir/exit_loop.h"
#include "src/tint/lang/core/ir/function.h"
-#include "src/tint/lang/core/ir/if.h"
#include "src/tint/lang/core/ir/load.h"
#include "src/tint/lang/core/ir/loop.h"
#include "src/tint/lang/core/ir/multi_in_block.h"
@@ -61,13 +58,6 @@
}
return false;
}
-
-bool IsConstantInteger(const Value* v) {
- if (auto* cv = v->As<Constant>()) {
- return cv->Type()->IsIntegerScalar();
- }
- return false;
-}
} // namespace
IntegerRangeInfo::IntegerRangeInfo(int64_t min_bound, int64_t max_bound) {
@@ -265,162 +255,6 @@
return add_or_sub_from_loop_control_variable;
}
- // Currently we only support the loop continuing of a simple for-loop which meets all the below
- // requirements:
- // - The loop control variable is only used as the parameter of the load instruction.
- // - The first instruction is to load the loop control variable into a temporary variable.
- // - The second instruction is to compare the temporary variable with a constant value and save
- // the result to a boolean variable.
- // - The second instruction cannot be a comparison that will never return true.
- // - The third instruction is an `ifelse` expression that uses the boolean variable got in the
- // second instruction as the condition.
- // - The true block of the above `ifelse` expression doesn't contain `exit_loop`.
- // - The false block of the above `ifelse` expression only contains `exit_loop`.
- const Binary* GetBinaryToCompareLoopControlVariableInLoopBody(
- const Loop* loop,
- const Var* loop_control_variable) {
- TINT_ASSERT(loop);
- TINT_ASSERT(loop_control_variable);
-
- auto* body_block = loop->Body();
-
- // Reject any non-load instructions unless it is a store in the continuing block
- const auto& uses = loop_control_variable->Result(0)->UsagesUnsorted();
- for (auto& use : uses) {
- if (use->instruction->Is<Load>()) {
- continue;
- }
- if (use->instruction->Is<Store>() && use->instruction->Block() == loop->Continuing()) {
- continue;
- }
- return nullptr;
- }
-
- // 1st instruction:
- // %src = load %loop_control_variable
- const auto* load_from_loop_control_variable = body_block->Instructions()->As<Load>();
- if (!load_from_loop_control_variable) {
- return nullptr;
- }
- if (load_from_loop_control_variable->From() != loop_control_variable->Result(0)) {
- return nullptr;
- }
-
- // 2nd instruction:
- // %condition:bool = lt(gt, lte, gte) %src, constant_value
- // or %condition:bool = lt(gt, lte, gte) constant_value, %src
- const auto* exit_condition_on_loop_control_variable =
- load_from_loop_control_variable->next->As<Binary>();
- if (!exit_condition_on_loop_control_variable) {
- return nullptr;
- }
- BinaryOp op = exit_condition_on_loop_control_variable->Op();
- auto* lhs = exit_condition_on_loop_control_variable->LHS();
- auto* rhs = exit_condition_on_loop_control_variable->RHS();
- switch (op) {
- case BinaryOp::kLessThan:
- case BinaryOp::kGreaterThan:
- case BinaryOp::kLessThanEqual:
- case BinaryOp::kGreaterThanEqual: {
- if (IsConstantInteger(rhs) && lhs == load_from_loop_control_variable->Result(0)) {
- break;
- }
- if (IsConstantInteger(lhs) && rhs == load_from_loop_control_variable->Result(0)) {
- break;
- }
- return nullptr;
- }
- default:
- return nullptr;
- }
-
- // Early-return when the comparison will never return true.
- if (op == BinaryOp::kLessThan) {
- if (IsConstantInteger(lhs)) {
- // std::numeric_limits<uint32_t>::max() < idx
- if (lhs->As<Constant>()->Value()->Type()->IsUnsignedIntegerScalar() &&
- lhs->As<Constant>()->Value()->ValueAs<uint32_t>() ==
- std::numeric_limits<uint32_t>::max()) {
- return nullptr;
- }
- // std::numeric_limits<int32_t>::max() < idx
- if (lhs->As<Constant>()->Value()->Type()->IsSignedIntegerScalar() &&
- lhs->As<Constant>()->Value()->ValueAs<int32_t>() ==
- std::numeric_limits<int32_t>::max()) {
- return nullptr;
- }
- } else {
- TINT_ASSERT(IsConstantInteger(rhs));
- // idx < 0u
- if (rhs->As<Constant>()->Value()->Type()->IsUnsignedIntegerScalar() &&
- rhs->As<Constant>()->Value()->ValueAs<uint32_t>() ==
- std::numeric_limits<uint32_t>::min()) {
- return nullptr;
- }
- // idx < std::numeric_limits<int32_t>::min()
- if (rhs->As<Constant>()->Value()->Type()->IsSignedIntegerScalar() &&
- rhs->As<Constant>()->Value()->ValueAs<int32_t>() ==
- std::numeric_limits<int32_t>::min()) {
- return nullptr;
- }
- }
- } else if (op == BinaryOp::kGreaterThan) {
- if (IsConstantInteger(lhs)) {
- // std::numeric_limits<uint32_t>::min() > idx
- if (lhs->As<Constant>()->Value()->Type()->IsUnsignedIntegerScalar() &&
- lhs->As<Constant>()->Value()->ValueAs<uint32_t>() ==
- std::numeric_limits<uint32_t>::min()) {
- return nullptr;
- }
- // std::numeric_limits<int32_t>::min() > idx
- if (lhs->As<Constant>()->Value()->Type()->IsSignedIntegerScalar() &&
- lhs->As<Constant>()->Value()->ValueAs<int32_t>() ==
- std::numeric_limits<int32_t>::min()) {
- return nullptr;
- }
- } else {
- TINT_ASSERT(IsConstantInteger(rhs));
- // idx > std::numeric_limits<uint32_t>::max()
- if (rhs->As<Constant>()->Value()->Type()->IsUnsignedIntegerScalar() &&
- rhs->As<Constant>()->Value()->ValueAs<uint32_t>() ==
- std::numeric_limits<uint32_t>::max()) {
- return nullptr;
- }
- // idx > std::numeric_limits<int32_t>::max()
- if (rhs->As<Constant>()->Value()->Type()->IsSignedIntegerScalar() &&
- rhs->As<Constant>()->Value()->ValueAs<int32_t>() ==
- std::numeric_limits<int32_t>::max()) {
- return nullptr;
- }
- }
- }
-
- // 3rd instruction:
- // if %condition [t: $true, f: $false] {
- // $true: {
- // // Maybe some other instructions
- // exit_if
- // }
- // $false: { exit_loop }
- // }
- const auto* if_on_exit_condition = exit_condition_on_loop_control_variable->next->As<If>();
- if (!if_on_exit_condition) {
- return nullptr;
- }
- if (if_on_exit_condition->Condition() !=
- exit_condition_on_loop_control_variable->Result(0)) {
- return nullptr;
- }
- if (!if_on_exit_condition->True()->Terminator()->As<ExitIf>()) {
- return nullptr;
- }
- if (!if_on_exit_condition->False()->Front()->As<ExitLoop>()) {
- return nullptr;
- }
-
- return exit_condition_on_loop_control_variable;
- }
-
private:
Function* function_;
Hashmap<const FunctionParam*, Vector<IntegerRangeInfo, 3>, 4>
@@ -447,10 +281,4 @@
loop_control_variable);
}
-const Binary* IntegerRangeAnalysis::GetBinaryToCompareLoopControlVariableInLoopBodyForTest(
- const Loop* loop,
- const Var* loop_control_variable) {
- return impl_->GetBinaryToCompareLoopControlVariableInLoopBody(loop, loop_control_variable);
-}
-
} // namespace tint::core::ir::analysis
diff --git a/src/tint/lang/core/ir/analysis/integer_range_analysis.h b/src/tint/lang/core/ir/analysis/integer_range_analysis.h
index d00e262..00576c5 100644
--- a/src/tint/lang/core/ir/analysis/integer_range_analysis.h
+++ b/src/tint/lang/core/ir/analysis/integer_range_analysis.h
@@ -102,8 +102,7 @@
/// - The third instruction is to store the value of the temporary variable into the loop
/// control variable.
/// - The fourth instruction is `next_iteration`.
- /// @param loop the Loop variable to investigate.
- /// @param loop_control_variable the loop control variable to investigate.
+ /// @param loop the Loop variable to investigate
/// @returns the pointer of the binary operation that updates the loop control variable in the
/// continuing block of the given loop if the loop meets all the requirements, return nullptr
/// otherwise.
@@ -111,27 +110,6 @@
const Loop* loop,
const Var* loop_control_variable);
- /// Note: This function is only for tests
- /// Returns the pointer of the binary operation that compares the loop control variable with its
- /// limitations in the body block of the loop if the loop meets the below requirements:
- /// - The loop control variable is only used as the parameter of the load instruction.
- /// - The first instruction is to load the loop control variable into a temporary variable.
- /// - The second instruction is to compare the temporary variable with a constant value and save
- /// the result to a boolean variable.
- /// - The second instruction cannot be a comparison that will never return true.
- /// - The third instruction is an `ifelse` expression that uses the boolean variable got in the
- /// second instruction as the condition.
- // - The true block of the above `ifelse` expression doesn't contain `exit_loop`.
- // - The false block of the above `ifelse` expression only contains `exit_loop`.
- /// @param loop the Loop variable to investigate.
- /// @param loop_control_variable the loop control variable to investigate.
- /// @returns the pointer of the binary operation that compares the loop control variable with
- /// its limitations in the body block of the loop if the loop meets the below requirements,
- /// return nullptr otherwise.
- const Binary* GetBinaryToCompareLoopControlVariableInLoopBodyForTest(
- const Loop* loop,
- const Var* loop_control_variable);
-
private:
IntegerRangeAnalysis(const IntegerRangeAnalysis&) = delete;
IntegerRangeAnalysis(IntegerRangeAnalysis&&) = delete;
diff --git a/src/tint/lang/core/ir/analysis/integer_range_analysis_test.cc b/src/tint/lang/core/ir/analysis/integer_range_analysis_test.cc
index 97b7aa2..9601f60 100644
--- a/src/tint/lang/core/ir/analysis/integer_range_analysis_test.cc
+++ b/src/tint/lang/core/ir/analysis/integer_range_analysis_test.cc
@@ -1562,2297 +1562,5 @@
analysis.GetBinaryToUpdateLoopControlVariableInContinuingBlockForTest(loop, idx));
}
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Success_index_LessThan_Constant) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // idx < 10
- binary = b.LessThan<bool>(b.Load(idx), 10_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = lt %3, 10i
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = add %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(binary, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Success_Constant_LessThan_index) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 20_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // 10 < idx
- binary = b.LessThan<bool>(10_i, b.Load(idx));
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Subtract<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 20i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = lt 10i, %3
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = sub %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(binary, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Success_index_LessThan_Constant_u32) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_u);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // idx < 10u
- binary = b.LessThan<bool>(b.Load(idx), 10_u);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<u32>(b.Load(idx), 1_u));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, u32, read_write> = var 0u
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:u32 = load %idx
- %4:bool = lt %3, 10u
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:u32 = load %idx
- %6:u32 = add %5, 1u
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(binary, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Success_Constant_LessThan_index_u32) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 20_u);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // 10u < idx
- binary = b.LessThan<bool>(10_u, b.Load(idx));
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Subtract<u32>(b.Load(idx), 1_u));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, u32, read_write> = var 20u
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:u32 = load %idx
- %4:bool = lt 10u, %3
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:u32 = load %idx
- %6:u32 = sub %5, 1u
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(binary, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Success_index_LessThanEqual_constant) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // idx <= 10
- binary = b.LessThanEqual<bool>(b.Load(idx), 10_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = lte %3, 10i
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = add %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(binary, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Success_constant_LessThanEqual_index) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 20_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // 10 <= idx
- binary = b.LessThanEqual<bool>(10_i, b.Load(idx));
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Subtract<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 20i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = lte 10i, %3
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = sub %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(binary, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Success_index_GreaterThan_constant) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- // idx > 20
- idx = b.Var("idx", 20_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- binary = b.GreaterThan<bool>(b.Load(idx), 10_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Subtract<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 20i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = gt %3, 10i
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = sub %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(binary, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Success_constant_GreaterThan_index) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // 10 > idx
- binary = b.GreaterThan<bool>(10_i, b.Load(idx));
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = gt 10i, %3
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = add %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(binary, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Success_index_GreaterThanEqual_Constant) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 20_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // idx >= 10
- binary = b.GreaterThanEqual<bool>(b.Load(idx), 10_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Subtract<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 20i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = gte %3, 10i
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = sub %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(binary, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Success_Constant_GreaterThanEqual_index) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // 10 >= idx
- binary = b.GreaterThanEqual<bool>(10_i, b.Load(idx));
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = gte 10i, %3
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = add %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(binary, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_InstructionsOtherThanLoadOnIndex) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* end = b.FunctionParam("end", ty.i32());
- auto* func = b.Function("func", ty.void_());
- func->AppendParam(end);
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 20_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- binary = b.GreaterThanEqual<bool>(10_i, b.Load(idx));
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Store(idx, end);
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Subtract<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func(%end:i32):void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 20i
- next_iteration # -> $B3
- }
- $B3: { # body
- %4:i32 = load %idx
- %5:bool = gte 10i, %4
- if %5 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- store %idx, %end
- continue # -> $B4
- }
- $B4: { # continuing
- %6:i32 = load %idx
- %7:i32 = sub %6, 1i
- store %idx, %7
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_FirstInstructionIsNotLoad) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // Initialize idy to 1
- Var* idy = b.Var("idy", 1_i);
- binary = b.LessThan<bool>(b.Load(idy), 10_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %idy:ptr<function, i32, read_write> = var 1i
- %4:i32 = load %idy
- %5:bool = lt %4, 10i
- if %5 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %6:i32 = load %idx
- %7:i32 = add %6, 1i
- store %idx, %7
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_NoLoadFromLoopControlVariable) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- Var* idy = b.Var("idy", 1_i);
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // idy < 10
- binary = b.LessThan<bool>(b.Load(idy), 10_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- %idy:ptr<function, i32, read_write> = var 1i
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %4:i32 = load %idy
- %5:bool = lt %4, 10i
- if %5 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %6:i32 = load %idx
- %7:i32 = add %6, 1i
- store %idx, %7
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_StoreLoopControlVariableInInnerBlock) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- Var* idy = b.Var("idy", 1_i);
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- binary = b.LessThan<bool>(b.Load(idx), 10_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- auto* ifelse_y = b.If(b.LessThan<bool>(b.Load(idy), 10_i));
- b.Append(ifelse_y->True(), [&] {
- b.Store(idx, 2_i);
- b.ExitIf(ifelse_y);
- });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- %idy:ptr<function, i32, read_write> = var 1i
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %4:i32 = load %idx
- %5:bool = lt %4, 10i
- if %5 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- %6:i32 = load %idy
- %7:bool = lt %6, 10i
- if %7 [t: $B7] { # if_2
- $B7: { # true
- store %idx, 2i
- exit_if # if_2
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %8:i32 = load %idx
- %9:i32 = add %8, 1i
- store %idx, %9
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_SecondInstructionNotABinaryOp) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // bitcastX = bitcast<i32>(idx)
- auto* bitcastX = b.Bitcast<i32>(b.Load(idx));
- binary = b.LessThan<bool>(bitcastX, 10_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:i32 = bitcast %3
- %5:bool = lt %4, 10i
- if %5 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %6:i32 = load %idx
- %7:i32 = add %6, 1i
- store %idx, %7
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_BinaryOpIsNotComparisonOp) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // shl = idx << 1
- auto* shl = b.ShiftLeft<i32>(b.Load(idx), 1_u);
- binary = b.LessThan<bool>(10_i, shl);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:i32 = shl %3, 1u
- %5:bool = lt 10i, %4
- if %5 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %6:i32 = load %idx
- %7:i32 = add %6, 1i
- store %idx, %7
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_IndexCompareWithNonConst) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* end = b.FunctionParam("end", ty.i32());
- auto* func = b.Function("func", ty.void_());
- func->AppendParam(end);
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // idx < end
- binary = b.LessThan<bool>(b.Load(idx), end);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func(%end:i32):void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %4:i32 = load %idx
- %5:bool = lt %4, %end
- if %5 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %6:i32 = load %idx
- %7:i32 = add %6, 1i
- store %idx, %7
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_NonConstCompareWithIndex) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* end = b.FunctionParam("end", ty.i32());
- auto* func = b.Function("func", ty.void_());
- func->AppendParam(end);
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 20_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // end > idx
- binary = b.GreaterThan<bool>(end, b.Load(idx));
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Subtract<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func(%end:i32):void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 20i
- next_iteration # -> $B3
- }
- $B3: { # body
- %4:i32 = load %idx
- %5:bool = gt %end, %4
- if %5 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %6:i32 = load %idx
- %7:i32 = sub %6, 1i
- store %idx, %7
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_NonIndexCompareWithConst) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* end = b.FunctionParam("end", ty.i32());
- auto* func = b.Function("func", ty.void_());
- func->AppendParam(end);
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- b.Load(idx);
- // end < 10
- binary = b.LessThan<bool>(end, 10_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func(%end:i32):void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %4:i32 = load %idx
- %5:bool = lt %end, 10i
- if %5 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %6:i32 = load %idx
- %7:i32 = add %6, 1i
- store %idx, %7
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_ConstCompareWithNonIndex) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* end = b.FunctionParam("end", ty.i32());
- auto* func = b.Function("func", ty.void_());
- func->AppendParam(end);
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 20_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- b.Load(idx);
- // 10 > end
- binary = b.GreaterThan<bool>(10_i, end);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Subtract<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func(%end:i32):void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 20i
- next_iteration # -> $B3
- }
- $B3: { # body
- %4:i32 = load %idx
- %5:bool = gt 10i, %end
- if %5 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %6:i32 = load %idx
- %7:i32 = sub %6, 1i
- store %idx, %7
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_Index_LessThan_Zero_u32) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_u);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // idx < 0u
- binary = b.LessThan<bool>(b.Load(idx), 0_u);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<u32>(b.Load(idx), 1_u));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, u32, read_write> = var 0u
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:u32 = load %idx
- %4:bool = lt %3, 0u
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:u32 = load %idx
- %6:u32 = add %5, 1u
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_Zero_GreaterThan_Index_u32) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_u);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // 0u > idx
- binary = b.GreaterThan<bool>(0_u, b.Load(idx));
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<u32>(b.Load(idx), 1_u));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, u32, read_write> = var 0u
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:u32 = load %idx
- %4:bool = gt 0u, %3
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:u32 = load %idx
- %6:u32 = add %5, 1u
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_Index_GreaterThan_Max_u32) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_u);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // idx > 4294967295u (maximum uint32_t value)
- binary = b.GreaterThan<bool>(b.Load(idx), 4294967295_u);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<u32>(b.Load(idx), 1_u));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, u32, read_write> = var 0u
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:u32 = load %idx
- %4:bool = gt %3, 4294967295u
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:u32 = load %idx
- %6:u32 = add %5, 1u
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_Max_u32_LessThan_Index) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_u);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // 4294967295u (maximum uint32_t value) < idx
- binary = b.LessThan<bool>(4294967295_u, b.Load(idx));
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<u32>(b.Load(idx), 1_u));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, u32, read_write> = var 0u
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:u32 = load %idx
- %4:bool = lt 4294967295u, %3
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:u32 = load %idx
- %6:u32 = add %5, 1u
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_Index_LessThan_Min_I32) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // idx < -2147483648 (minimum int32_t value)
- binary = b.LessThan<bool>(b.Load(idx), -2147483648_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Subtract<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = lt %3, -2147483648i
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = sub %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_Min_I32_GreaterThan_Index) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // -2147483648 (minimum int32_t value) > idx
- binary = b.GreaterThan<bool>(-2147483648_i, b.Load(idx));
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Subtract<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = gt -2147483648i, %3
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = sub %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_Index_GreaterThan_Max_I32) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // idx > 2147483647 (maximum int32_t value)
- binary = b.GreaterThan<bool>(b.Load(idx), 2147483647_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Subtract<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = gt %3, 2147483647i
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = sub %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_Max_I32_LessThan_Index) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- // 2147483647i (maximum int32_t value) < idx
- binary = b.LessThan<bool>(2147483647_i, b.Load(idx));
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Subtract<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = lt 2147483647i, %3
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = sub %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_NotIfElseAfterCompareInstruction) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- binary = b.LessThan<bool>(b.Load(idx), 10_i);
- // Now idx can be 10 before the if-statement
- b.Add<i32>(b.Load(idx), 1_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = lt %3, 10i
- %5:i32 = load %idx
- %6:i32 = add %5, 1i
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %7:i32 = load %idx
- %8:i32 = add %7, 1i
- store %idx, %8
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_NotUseLastComparisonAsIfCondition) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* param = b.FunctionParam("param", ty.i32());
- auto* func = b.Function("func", ty.void_());
- func->AppendParam(param);
- b.Append(func->Block(), [&] {
- Binary* binaryOnParam = b.LessThan<bool>(param, 30_i);
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- binary = b.LessThan<bool>(b.Load(idx), 10_i);
- auto* ifelse = b.If(binaryOnParam);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func(%param:i32):void {
- $B1: {
- %3:bool = lt %param, 30i
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %5:i32 = load %idx
- %6:bool = lt %5, 10i
- if %3 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %7:i32 = load %idx
- %8:i32 = add %7, 1i
- store %idx, %8
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Success_MultipleInstructionsInTrueBlock) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- binary = b.LessThan<bool>(b.Load(idx), 10_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] {
- // Now idx < 10
- b.Add<i32>(b.Load(idx), 30_i);
- b.ExitIf(ifelse);
- });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = lt %3, 10i
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- %5:i32 = load %idx
- %6:i32 = add %5, 30i
- exit_if # if_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %7:i32 = load %idx
- %8:i32 = add %7, 1i
- store %idx, %8
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(binary, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_ExitLoopInTrueBlock) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- binary = b.LessThan<bool>(b.Load(idx), 10_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitLoop(loop); });
- b.Append(ifelse->False(), [&] { b.ExitLoop(loop); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = lt %3, 10i
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_loop # loop_1
- }
- $B6: { # false
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = add %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_TooManyInstructionsInFalseBlock) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- binary = b.LessThan<bool>(b.Load(idx), 10_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] {
- // Now idx can be 10
- b.Load(idx);
- b.ExitLoop(loop);
- });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = lt %3, 10i
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- %5:i32 = load %idx
- exit_loop # loop_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %6:i32 = load %idx
- %7:i32 = add %6, 1i
- store %idx, %7
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
-TEST_F(IR_IntegerRangeAnalysisTest, AnalyzeLoopBody_Failure_NoExitLoopInFalseBlock) {
- Var* idx = nullptr;
- Loop* loop = nullptr;
- Binary* binary = nullptr;
- auto* func = b.Function("func", ty.void_());
- b.Append(func->Block(), [&] {
- loop = b.Loop();
- b.Append(loop->Initializer(), [&] {
- idx = b.Var("idx", 0_i);
- b.NextIteration(loop);
- });
- b.Append(loop->Body(), [&] {
- binary = b.LessThan<bool>(b.Load(idx), 10_i);
- auto* ifelse = b.If(binary);
- b.Append(ifelse->True(), [&] { b.ExitIf(ifelse); });
- b.Append(ifelse->False(), [&] { b.ExitIf(ifelse); });
- b.Continue(loop);
- });
- b.Append(loop->Continuing(), [&] {
- b.Store(idx, b.Add<i32>(b.Load(idx), 1_i));
- b.NextIteration(loop);
- });
- b.Return(func);
- });
-
- auto* src = R"(
-%func = func():void {
- $B1: {
- loop [i: $B2, b: $B3, c: $B4] { # loop_1
- $B2: { # initializer
- %idx:ptr<function, i32, read_write> = var 0i
- next_iteration # -> $B3
- }
- $B3: { # body
- %3:i32 = load %idx
- %4:bool = lt %3, 10i
- if %4 [t: $B5, f: $B6] { # if_1
- $B5: { # true
- exit_if # if_1
- }
- $B6: { # false
- exit_if # if_1
- }
- }
- continue # -> $B4
- }
- $B4: { # continuing
- %5:i32 = load %idx
- %6:i32 = add %5, 1i
- store %idx, %6
- next_iteration # -> $B3
- }
- }
- ret
- }
-}
-)";
- EXPECT_EQ(src, str());
- EXPECT_EQ(Validate(mod), Success);
-
- IntegerRangeAnalysis analysis(func);
- EXPECT_EQ(idx, analysis.GetLoopControlVariableFromConstantInitializerForTest(loop));
- EXPECT_EQ(nullptr, analysis.GetBinaryToCompareLoopControlVariableInLoopBodyForTest(loop, idx));
-}
-
} // namespace
} // namespace tint::core::ir::analysis
diff --git a/src/tint/lang/core/ir/value.h b/src/tint/lang/core/ir/value.h
index 54879fa..c2475b6 100644
--- a/src/tint/lang/core/ir/value.h
+++ b/src/tint/lang/core/ir/value.h
@@ -104,7 +104,7 @@
/// @returns the set of usages of this value. An instruction may appear multiple times if it
/// uses the value for multiple different operands.
- const Hashset<Usage, 4>& UsagesUnsorted() const { return uses_; }
+ const Hashset<Usage, 4>& UsagesUnsorted() { return uses_; }
/// @returns a sorted list of usages of this value. The usages are in the order of
/// <instruction, operand index> where the instructions are ordered earliest instruction to