Skip to content

Commit 5c9f495

Browse files
committed
LLVMLoopAnalyzer: Implement nested loops in variableTypeChanges()
1 parent da38039 commit 5c9f495

File tree

3 files changed

+514
-38
lines changed

3 files changed

+514
-38
lines changed

src/engine/internal/llvm/llvmloopanalyzer.cpp

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
using namespace libscratchcpp;
88

9+
static const std::unordered_set<LLVMInstruction::Type>
10+
BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop };
11+
912
bool LLVMLoopAnalyzer::variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const
1013
{
1114
if (!varPtr || !loopBody)
@@ -14,23 +17,80 @@ bool LLVMLoopAnalyzer::variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruct
1417
if (preLoopType == Compiler::StaticType::Unknown)
1518
return true;
1619

17-
// Find the last write instruction
18-
LLVMInstruction *lastVarWrite = nullptr;
19-
LLVMInstruction *ins = loopBody;
20+
// Find loop end
21+
LLVMInstruction *ins = loopBody->next;
22+
int loopLevel = 0;
2023

21-
while (ins && ins->type != LLVMInstruction::Type::EndLoop) {
22-
// TODO: Handle nested loops
23-
if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var)
24-
lastVarWrite = ins;
24+
while (ins && !(isLoopEnd(ins) && loopLevel == 0)) {
25+
if (isLoopStart(ins))
26+
loopLevel++;
27+
else if (isLoopEnd(ins)) {
28+
assert(loopLevel > 0);
29+
loopLevel--;
30+
}
2531

2632
ins = ins->next;
2733
}
2834

2935
// Loops must always have an end instruction
30-
assert(ins);
36+
if (!ins) {
37+
assert(false);
38+
return true;
39+
}
3140

32-
// Check the last write instruction, if any
33-
return lastVarWrite ? !typesMatch(lastVarWrite, preLoopType) : false;
41+
return variableTypeChangesFromEnd(varPtr, ins, preLoopType);
42+
}
43+
44+
bool LLVMLoopAnalyzer::variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const
45+
{
46+
// Find the last write instruction
47+
LLVMInstruction *ins = loopEnd->previous;
48+
49+
while (ins && !isLoopStart(ins)) {
50+
if (isLoopEnd(ins)) {
51+
// Nested loop
52+
if (variableTypeChangesFromEnd(varPtr, ins, preLoopType))
53+
return true;
54+
55+
// Skip the loop
56+
int loopLevel = 0;
57+
ins = ins->previous;
58+
59+
while (ins && !(isLoopStart(ins) && loopLevel == 0)) {
60+
if (isLoopStart(ins)) {
61+
assert(loopLevel > 0);
62+
loopLevel--;
63+
}
64+
65+
if (isLoopEnd(ins))
66+
loopLevel++;
67+
68+
ins = ins->previous;
69+
};
70+
71+
if (!ins) {
72+
assert(false);
73+
return true;
74+
}
75+
} else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
76+
// Variable write instruction
77+
return !typesMatch(ins, preLoopType);
78+
}
79+
80+
ins = ins->previous;
81+
}
82+
83+
return false;
84+
}
85+
86+
bool LLVMLoopAnalyzer::isLoopStart(LLVMInstruction *ins) const
87+
{
88+
return (BEGIN_LOOP_INSTRUCTIONS.find(ins->type) != BEGIN_LOOP_INSTRUCTIONS.cend());
89+
}
90+
91+
bool LLVMLoopAnalyzer::isLoopEnd(LLVMInstruction *ins) const
92+
{
93+
return (ins->type == LLVMInstruction::Type::EndLoop);
3494
}
3595

3696
Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) const

src/engine/internal/llvm/llvmloopanalyzer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ class LLVMLoopAnalyzer
1515
bool variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const;
1616

1717
private:
18+
bool variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const;
19+
bool isLoopStart(LLVMInstruction *ins) const;
20+
bool isLoopEnd(LLVMInstruction *ins) const;
21+
1822
Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
1923
bool typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const;
2024
};

0 commit comments

Comments
 (0)