Skip to content

Commit 82c8f0e

Browse files
committed
LLVMCodeAnalyzer: Fix reads in loop conditions
1 parent 02868ee commit 82c8f0e

File tree

3 files changed

+69
-13
lines changed

3 files changed

+69
-13
lines changed

src/engine/internal/llvm/llvmcodeanalyzer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
using namespace libscratchcpp;
99

10-
static const std::unordered_set<LLVMInstruction::Type>
11-
BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop };
10+
// NOTE: The loop condition in repeat until and while loops is considered a part of the loop body
11+
static const std::unordered_set<LLVMInstruction::Type> BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginLoopCondition };
1212

1313
static const std::unordered_set<LLVMInstruction::Type> LIST_WRITE_INSTRUCTIONS = { LLVMInstruction::Type::AppendToList, LLVMInstruction::Type::InsertToList, LLVMInstruction::Type::ListReplace };
1414

test/llvm/code_analyzer/list_type_analysis.cpp

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, ClearAfterWriteInLoop)
529529
appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
530530
list.addInstruction(appendList);
531531

532-
auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, false);
532+
auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
533533
list.addInstruction(loopStart);
534534

535535
auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
@@ -567,25 +567,38 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, WhileLoop)
567567
appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
568568
list.addInstruction(appendList);
569569

570+
auto loopCond = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginLoopCondition, false);
571+
list.addInstruction(loopCond);
572+
573+
// Read an item in loop condition
574+
auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
575+
LLVMConstantRegister index(Compiler::StaticType::Number, 0);
576+
getItem->targetList = &targetList;
577+
getItem->args.push_back({ Compiler::StaticType::Number, &index });
578+
list.addInstruction(getItem);
579+
580+
LLVMRegister sourceValue(Compiler::StaticType::Unknown);
581+
sourceValue.isRawValue = false;
582+
sourceValue.instruction = getItem;
583+
getItem->functionReturnReg = &sourceValue;
584+
570585
auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, false);
571586
list.addInstruction(loopStart);
572587

588+
// Change the type in the loop
573589
auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
574590
LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
575591
appendList1->targetList = &targetList;
576592
appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
577593
list.addInstruction(appendList1);
578594

579-
auto clearList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
580-
clearList2->targetList = &targetList;
581-
list.addInstruction(clearList2);
582-
583595
auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
584596
list.addInstruction(loopEnd);
585597

586598
analyzer.analyzeScript(list);
587599

588-
ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Bool);
600+
ASSERT_EQ(getItem->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool);
601+
ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool);
589602
}
590603

591604
TEST(LLVMCodeAnalyzer_ListTypeAnalysis, RepeatUntilLoop)
@@ -605,25 +618,38 @@ TEST(LLVMCodeAnalyzer_ListTypeAnalysis, RepeatUntilLoop)
605618
appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
606619
list.addInstruction(appendList);
607620

621+
auto loopCond = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginLoopCondition, false);
622+
list.addInstruction(loopCond);
623+
624+
// Read an item in loop condition
625+
auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
626+
LLVMConstantRegister index(Compiler::StaticType::Number, 0);
627+
getItem->targetList = &targetList;
628+
getItem->args.push_back({ Compiler::StaticType::Number, &index });
629+
list.addInstruction(getItem);
630+
631+
LLVMRegister sourceValue(Compiler::StaticType::Unknown);
632+
sourceValue.isRawValue = false;
633+
sourceValue.instruction = getItem;
634+
getItem->functionReturnReg = &sourceValue;
635+
608636
auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, false);
609637
list.addInstruction(loopStart);
610638

639+
// Change the type in the loop
611640
auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
612641
LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
613642
appendList1->targetList = &targetList;
614643
appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
615644
list.addInstruction(appendList1);
616645

617-
auto clearList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
618-
clearList2->targetList = &targetList;
619-
list.addInstruction(clearList2);
620-
621646
auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
622647
list.addInstruction(loopEnd);
623648

624649
analyzer.analyzeScript(list);
625650

626-
ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Bool);
651+
ASSERT_EQ(getItem->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool);
652+
ASSERT_EQ(appendList1->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool);
627653
}
628654

629655
TEST(LLVMCodeAnalyzer_ListTypeAnalysis, LoopMultipleWrites_UnknownType)

test/llvm/code_analyzer/variable_type_analysis.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,23 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WhileLoop)
144144
setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
145145
list.addInstruction(setVar);
146146

147+
auto loopCond = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginLoopCondition, false);
148+
list.addInstruction(loopCond);
149+
150+
// Read the variable in loop condition
151+
auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, true);
152+
readVar->targetVariable = &var;
153+
list.addInstruction(readVar);
154+
155+
LLVMRegister varValue(Compiler::StaticType::Unknown);
156+
varValue.isRawValue = false;
157+
varValue.instruction = readVar;
158+
readVar->functionReturnReg = &varValue;
159+
147160
auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, false);
148161
list.addInstruction(loopStart);
149162

163+
// Change the type in the loop
150164
auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
151165
LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
152166
setVar1->targetVariable = &var;
@@ -158,6 +172,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, WhileLoop)
158172

159173
analyzer.analyzeScript(list);
160174

175+
ASSERT_EQ(readVar->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool);
161176
ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool);
162177
}
163178

@@ -174,9 +189,23 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, RepeatUntilLoop)
174189
setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
175190
list.addInstruction(setVar);
176191

192+
auto loopCond = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginLoopCondition, false);
193+
list.addInstruction(loopCond);
194+
195+
// Read the variable in loop condition
196+
auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, true);
197+
readVar->targetVariable = &var;
198+
list.addInstruction(readVar);
199+
200+
LLVMRegister varValue(Compiler::StaticType::Unknown);
201+
varValue.isRawValue = false;
202+
varValue.instruction = readVar;
203+
readVar->functionReturnReg = &varValue;
204+
177205
auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, false);
178206
list.addInstruction(loopStart);
179207

208+
// Change the type in the loop
180209
auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
181210
LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
182211
setVar1->targetVariable = &var;
@@ -188,6 +217,7 @@ TEST(LLVMCodeAnalyzer_VariableTypeAnalysis, RepeatUntilLoop)
188217

189218
analyzer.analyzeScript(list);
190219

220+
ASSERT_EQ(readVar->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool);
191221
ASSERT_EQ(setVar1->targetType, Compiler::StaticType::Number | Compiler::StaticType::Bool);
192222
}
193223

0 commit comments

Comments
 (0)