Skip to content

Commit c9342a9

Browse files
committed
LLVMTypeAnalyzer: Implement listTypeAfterBranch() for basic cases
1 parent 005357a commit c9342a9

File tree

4 files changed

+1745
-0
lines changed

4 files changed

+1745
-0
lines changed

src/engine/internal/llvm/llvmtypeanalyzer.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ using namespace libscratchcpp;
88
static const std::unordered_set<LLVMInstruction::Type>
99
BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop };
1010

11+
static const std::unordered_set<LLVMInstruction::Type> LIST_WRITE_INSTRUCTIONS = { LLVMInstruction::Type::AppendToList, LLVMInstruction::Type::InsertToList, LLVMInstruction::Type::ListReplace };
12+
1113
Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const
1214
{
1315
InstructionSet visitedInstructions;
@@ -20,6 +22,68 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL
2022
return variableTypeAfterBranch(var, start, previousType, visitedInstructions);
2123
}
2224

25+
Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const
26+
{
27+
if (!list || !start)
28+
return previousType;
29+
30+
assert(isLoopStart(start) || isIfStart(start) || isElse(start));
31+
32+
InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies
33+
34+
LLVMInstruction *ins = start->next;
35+
LLVMInstruction *lastWrite = nullptr;
36+
Compiler::StaticType lastWriteType = Compiler::StaticType::Unknown;
37+
int level = 0;
38+
39+
while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) {
40+
if (isLoopStart(ins) || isIfStart(ins))
41+
level++;
42+
else if (isLoopEnd(ins) || isIfEnd(ins)) {
43+
assert(level > 0);
44+
level--;
45+
} else if (isListWrite(ins, list)) {
46+
// List write instruction
47+
Compiler::StaticType writeType = writeValueType(ins, visitedInstructions);
48+
49+
// For non-empty lists, we can just check the write type
50+
if (!isEmpty && !typesMatch(writeType, previousType)) {
51+
return Compiler::StaticType::Unknown;
52+
}
53+
54+
// In empty lists, writes of the same type determine the final type
55+
if (isEmpty) {
56+
if (lastWrite) {
57+
// There was a write before which means it might determine the final type
58+
if (!typesMatch(writeType, lastWriteType))
59+
return Compiler::StaticType::Unknown;
60+
} else {
61+
// This is the first write found, it might determine the final type
62+
lastWrite = ins;
63+
lastWriteType = writeType;
64+
}
65+
}
66+
}
67+
68+
ins = ins->next;
69+
}
70+
71+
assert(ins);
72+
73+
if (isEmpty) {
74+
if (lastWrite) {
75+
// Only writes of the same type modify the list
76+
return lastWriteType;
77+
} else {
78+
// No writes to empty list found, keep the previous type
79+
return previousType;
80+
}
81+
} else {
82+
// No type conflicts found for non-empty list
83+
return previousType;
84+
}
85+
}
86+
2387
Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const
2488
{
2589
if (!var || !pos)
@@ -258,6 +322,11 @@ bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, Variable *var) cons
258322
return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == var);
259323
}
260324

325+
bool LLVMTypeAnalyzer::isListWrite(LLVMInstruction *ins, List *list) const
326+
{
327+
return (LIST_WRITE_INSTRUCTIONS.find(ins->type) != LIST_WRITE_INSTRUCTIONS.cend() && ins->workList == list);
328+
}
329+
261330
Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) const
262331
{
263332
// TODO: Move this method out if it's used in LLVMCodeBuilder too

src/engine/internal/llvm/llvmtypeanalyzer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ class LLVMTypeAnalyzer
1414
Compiler::StaticType variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const;
1515
Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const;
1616

17+
Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const;
18+
1719
private:
1820
using InstructionSet = std::unordered_set<LLVMInstruction *>;
1921

@@ -29,9 +31,12 @@ class LLVMTypeAnalyzer
2931
bool isIfStart(LLVMInstruction *ins) const;
3032
bool isElse(LLVMInstruction *ins) const;
3133
bool isIfEnd(LLVMInstruction *ins) const;
34+
3235
bool isVariableRead(LLVMInstruction *ins) const;
3336
bool isVariableWrite(LLVMInstruction *ins, Variable *var) const;
3437

38+
bool isListWrite(LLVMInstruction *ins, List *list) const;
39+
3540
Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
3641
bool isWriteNoOp(LLVMInstruction *ins) const;
3742
Compiler::StaticType writeValueType(LLVMInstruction *ins, InstructionSet &visitedInstructions) const;

test/llvm/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ add_executable(
2222
llvminstructionlist_test.cpp
2323
type_analyzer/variabletypeafterbranch_test.cpp
2424
type_analyzer/variabletype_test.cpp
25+
type_analyzer/listtypeafterbranch_test.cpp
2526
)
2627

2728
target_link_libraries(

0 commit comments

Comments
 (0)