Skip to content

Commit f9afdfc

Browse files
committed
LLVMTypeAnalyzer: Handle list clear instruction
1 parent c9342a9 commit f9afdfc

File tree

3 files changed

+762
-55
lines changed

3 files changed

+762
-55
lines changed

src/engine/internal/llvm/llvmtypeanalyzer.cpp

Lines changed: 57 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -27,61 +27,8 @@ Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstr
2727
if (!list || !start)
2828
return previousType;
2929

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-
}
30+
bool write = false; // only used internally (the compiler doesn't need this)
31+
return listTypeAfterBranch(list, start, previousType, isEmpty, write);
8532
}
8633

8734
Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const
@@ -234,6 +181,61 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
234181
return previousType;
235182
}
236183

184+
Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, bool &write) const
185+
{
186+
assert(isLoopStart(start) || isIfStart(start) || isElse(start));
187+
188+
InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies
189+
190+
LLVMInstruction *ins = start->next;
191+
write = false;
192+
193+
while (ins && !(isLoopEnd(ins) || isIfEnd(ins) || isElse(ins))) {
194+
if (isLoopStart(ins) || isIfStart(ins)) {
195+
do {
196+
Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, write);
197+
198+
// If there was a write, the list is no longer empty
199+
if (write) {
200+
isEmpty = false;
201+
202+
// The write could change the type
203+
if (!typesMatch(type, previousType))
204+
return Compiler::StaticType::Unknown;
205+
}
206+
207+
// Skip the branch
208+
ins = branchEnd(ins);
209+
} while (isElse(ins)); // handle else branch
210+
} else if (isListWrite(ins, list)) {
211+
// List write instruction
212+
Compiler::StaticType writeType = writeValueType(ins, visitedInstructions);
213+
write = true;
214+
215+
if (isEmpty) {
216+
// In empty lists, writes of the same type determine the final type
217+
// This is the first write found, it might determine the final type
218+
previousType = writeType;
219+
220+
// The list is no longer empty
221+
isEmpty = false;
222+
} else if (!typesMatch(writeType, previousType)) {
223+
// For non-empty lists, we can just check the write type
224+
return Compiler::StaticType::Unknown;
225+
}
226+
} else if (ins->type == LLVMInstruction::Type::ClearList && ins->workList == list) {
227+
// The list is now empty
228+
isEmpty = true;
229+
write = false; // the write variable is only used to check if the list is still empty
230+
}
231+
232+
ins = ins->next;
233+
}
234+
235+
assert(ins);
236+
return previousType;
237+
}
238+
237239
LLVMInstruction *LLVMTypeAnalyzer::branchEnd(LLVMInstruction *start) const
238240
{
239241
assert(start);

src/engine/internal/llvm/llvmtypeanalyzer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class LLVMTypeAnalyzer
2323
Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const;
2424
Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const;
2525

26+
Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, bool &write) const;
27+
2628
LLVMInstruction *branchEnd(LLVMInstruction *start) const;
2729
LLVMInstruction *branchStart(LLVMInstruction *end) const;
2830

0 commit comments

Comments
 (0)