Skip to content

Commit 5b0c770

Browse files
committed
LLVMLoopAnalyzer: Handle if statements in variableTypeChanges()
1 parent 5c9f495 commit 5b0c770

File tree

3 files changed

+150
-10
lines changed

3 files changed

+150
-10
lines changed

src/engine/internal/llvm/llvmloopanalyzer.cpp

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,23 @@ bool LLVMLoopAnalyzer::variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMI
4747
LLVMInstruction *ins = loopEnd->previous;
4848

4949
while (ins && !isLoopStart(ins)) {
50-
if (isLoopEnd(ins)) {
51-
// Nested loop
50+
if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
51+
// Nested loop or if statement
5252
if (variableTypeChangesFromEnd(varPtr, ins, preLoopType))
5353
return true;
5454

55-
// Skip the loop
56-
int loopLevel = 0;
55+
// Skip the loop or if statement
56+
int level = 0;
5757
ins = ins->previous;
5858

59-
while (ins && !(isLoopStart(ins) && loopLevel == 0)) {
60-
if (isLoopStart(ins)) {
61-
assert(loopLevel > 0);
62-
loopLevel--;
59+
while (ins && !((isLoopStart(ins) || isIfStart(ins) || isElse(ins)) && level == 0)) {
60+
if (isLoopStart(ins) || isIfStart(ins)) {
61+
assert(level > 0);
62+
level--;
6363
}
6464

65-
if (isLoopEnd(ins))
66-
loopLevel++;
65+
if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins))
66+
level++;
6767

6868
ins = ins->previous;
6969
};
@@ -93,6 +93,21 @@ bool LLVMLoopAnalyzer::isLoopEnd(LLVMInstruction *ins) const
9393
return (ins->type == LLVMInstruction::Type::EndLoop);
9494
}
9595

96+
bool LLVMLoopAnalyzer::isIfStart(LLVMInstruction *ins) const
97+
{
98+
return (ins->type == LLVMInstruction::Type::BeginIf);
99+
}
100+
101+
bool LLVMLoopAnalyzer::isElse(LLVMInstruction *ins) const
102+
{
103+
return (ins->type == LLVMInstruction::Type::BeginElse);
104+
}
105+
106+
bool LLVMLoopAnalyzer::isIfEnd(LLVMInstruction *ins) const
107+
{
108+
return (ins->type == LLVMInstruction::Type::EndIf);
109+
}
110+
96111
Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) const
97112
{
98113
// TODO: Move this method out if it's used in LLVMCodeBuilder too

src/engine/internal/llvm/llvmloopanalyzer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ class LLVMLoopAnalyzer
1818
bool variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const;
1919
bool isLoopStart(LLVMInstruction *ins) const;
2020
bool isLoopEnd(LLVMInstruction *ins) const;
21+
bool isIfStart(LLVMInstruction *ins) const;
22+
bool isElse(LLVMInstruction *ins) const;
23+
bool isIfEnd(LLVMInstruction *ins) const;
2124

2225
Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
2326
bool typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const;

test/llvm/loop_analyzer/variabletypechanges_test.cpp

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,128 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptim
647647
ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
648648
}
649649

650+
TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInIfBranch)
651+
{
652+
LLVMLoopAnalyzer analyzer;
653+
LLVMInstructionList list;
654+
LLVMVariablePtr varPtr;
655+
Variable var("", "");
656+
varPtr.var = &var;
657+
658+
auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
659+
list.addInstruction(start);
660+
661+
auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
662+
list.addInstruction(ifStart);
663+
664+
// First write - changes type
665+
auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
666+
LLVMConstantRegister value1(Compiler::StaticType::String, "test");
667+
setVar1->workVariable = &var;
668+
setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
669+
list.addInstruction(setVar1);
670+
671+
auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
672+
list.addInstruction(elseStart);
673+
674+
// Second write - does not change type
675+
auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
676+
LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
677+
setVar2->workVariable = &var;
678+
setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
679+
list.addInstruction(setVar2);
680+
681+
auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
682+
list.addInstruction(ifEnd);
683+
684+
auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
685+
list.addInstruction(end);
686+
687+
// Returns true because the type-changing branch might run
688+
ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
689+
}
690+
691+
TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInElseBranch)
692+
{
693+
LLVMLoopAnalyzer analyzer;
694+
LLVMInstructionList list;
695+
LLVMVariablePtr varPtr;
696+
Variable var("", "");
697+
varPtr.var = &var;
698+
699+
auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
700+
list.addInstruction(start);
701+
702+
auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
703+
list.addInstruction(ifStart);
704+
705+
// First write - does not change type
706+
auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
707+
LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
708+
setVar1->workVariable = &var;
709+
setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
710+
list.addInstruction(setVar1);
711+
712+
auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
713+
list.addInstruction(elseStart);
714+
715+
// Second write - changes type
716+
auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
717+
LLVMConstantRegister value2(Compiler::StaticType::String, "test");
718+
setVar2->workVariable = &var;
719+
setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
720+
list.addInstruction(setVar2);
721+
722+
auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
723+
list.addInstruction(ifEnd);
724+
725+
auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
726+
list.addInstruction(end);
727+
728+
// Returns true because the type-changing branch might run
729+
ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
730+
}
731+
732+
TEST(LLVMLoopAnalyzer_VariableTypeChanges, IfElseWithoutTypeChange)
733+
{
734+
LLVMLoopAnalyzer analyzer;
735+
LLVMInstructionList list;
736+
LLVMVariablePtr varPtr;
737+
Variable var("", "");
738+
varPtr.var = &var;
739+
740+
auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
741+
list.addInstruction(start);
742+
743+
auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
744+
list.addInstruction(ifStart);
745+
746+
// First write - does not change type
747+
auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
748+
LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
749+
setVar1->workVariable = &var;
750+
setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
751+
list.addInstruction(setVar1);
752+
753+
auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
754+
list.addInstruction(elseStart);
755+
756+
// Second write - does not change type
757+
auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
758+
LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
759+
setVar2->workVariable = &var;
760+
setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
761+
list.addInstruction(setVar2);
762+
763+
auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
764+
list.addInstruction(ifEnd);
765+
766+
auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
767+
list.addInstruction(end);
768+
769+
ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
770+
}
771+
650772
TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChange)
651773
{
652774
LLVMLoopAnalyzer analyzer;

0 commit comments

Comments
 (0)