Skip to content

Commit 6cddc41

Browse files
committed
LLVMTypeAnalyzer: Handle all nested loop/if statement cases
1 parent ee90056 commit 6cddc41

File tree

3 files changed

+878
-15
lines changed

3 files changed

+878
-15
lines changed

src/engine/internal/llvm/llvmtypeanalyzer.cpp

Lines changed: 99 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,23 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV
1717
// Check the last write operation before the instruction
1818
LLVMInstruction *ins = pos;
1919
LLVMInstruction *write = nullptr;
20-
LLVMInstruction *loopStart = nullptr;
20+
LLVMInstruction *firstBranch = nullptr;
21+
LLVMInstruction *firstElseBranch = nullptr;
2122
int level = 0;
2223

2324
while (ins) {
24-
if (isLoopEnd(ins))
25+
if (isLoopEnd(ins) || isIfEnd(ins))
2526
level++;
26-
else if (isLoopStart(ins)) {
27+
else if (isLoopStart(ins) || isIfStart(ins)) {
2728
level--;
28-
29-
if (!loopStart)
30-
loopStart = ins;
29+
firstBranch = ins;
30+
} else if (isElse(ins)) {
31+
// Skip if branch if coming from else
32+
firstElseBranch = ins;
33+
ins = skipBranch(ins);
34+
continue;
3135
} else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
32-
if (level <= 0) { // ignore nested loops (they're handled later)
36+
if (level <= 0) { // ignore nested branches (they're handled by the branch analyzer)
3337
write = ins;
3438
break;
3539
}
@@ -38,12 +42,20 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV
3842
ins = ins->previous;
3943
}
4044

41-
if (loopStart) {
42-
// Analyze the first loop that was found
43-
if (variableTypeChangesInBranch(varPtr, loopStart, previousType))
44-
return write ? writeValueType(write) : Compiler::StaticType::Unknown;
45+
if (firstBranch) {
46+
// Analyze the first branch and else branch
47+
if (write)
48+
previousType = writeValueType(write); // write operation overrides previous type
49+
50+
Compiler::StaticType firstBranchType = variableTypeAfterBranch(varPtr, firstBranch, previousType);
51+
Compiler::StaticType elseBranchType = variableTypeAfterBranch(varPtr, firstElseBranch, previousType);
52+
53+
if (typesMatch(firstBranchType, elseBranchType))
54+
return firstBranchType;
55+
else
56+
return Compiler::StaticType::Unknown;
4557
} else if (write) {
46-
// There wasn't any loop found, so we can just check the last write operation
58+
// There wasn't any branch found, so we can just check the last write operation
4759
return writeValueType(write);
4860
}
4961

@@ -82,6 +94,72 @@ bool LLVMTypeAnalyzer::variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVM
8294
return variableTypeChangesInBranchFromEnd(varPtr, ins, previousType);
8395
}
8496

97+
Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const
98+
{
99+
if (!varPtr || !start)
100+
return previousType;
101+
102+
assert(isLoopStart(start) || isIfStart(start) || isElse(start));
103+
104+
// Find loop/if statement end or else branch
105+
LLVMInstruction *ins = start->next;
106+
int level = 0;
107+
108+
while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) {
109+
if (isLoopStart(ins) || isIfStart(ins))
110+
level++;
111+
else if (isLoopEnd(ins) || isIfEnd(ins)) {
112+
assert(level > 0);
113+
level--;
114+
}
115+
116+
ins = ins->next;
117+
}
118+
119+
if (!ins) {
120+
assert(false);
121+
return Compiler::StaticType::Unknown;
122+
}
123+
124+
// Process the branch from end
125+
return variableTypeAfterBranchFromEnd(varPtr, ins, previousType);
126+
}
127+
128+
Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const
129+
{
130+
// Find the last write instruction
131+
LLVMInstruction *ins = end->previous;
132+
133+
while (ins && !isLoopStart(ins) && !isIfStart(ins)) {
134+
if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
135+
// Process the nested loop or if statement
136+
Compiler::StaticType ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType);
137+
138+
if (!typesMatch(ret, previousType))
139+
return ret;
140+
141+
ins = skipBranch(ins);
142+
143+
if (isElse(ins)) {
144+
// Process if branch (the else branch is already processed)
145+
ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType);
146+
147+
if (!typesMatch(ret, previousType))
148+
return ret;
149+
150+
ins = skipBranch(ins);
151+
}
152+
} else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
153+
// Variable write instruction
154+
return writeValueType(ins);
155+
}
156+
157+
ins = ins->previous;
158+
}
159+
160+
return previousType;
161+
}
162+
85163
bool LLVMTypeAnalyzer::variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const
86164
{
87165
// Find the last write instruction
@@ -104,7 +182,7 @@ bool LLVMTypeAnalyzer::variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPt
104182
}
105183
} else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
106184
// Variable write instruction
107-
return !typesMatch(ins, previousType);
185+
return !writeTypesMatch(ins, previousType);
108186
}
109187

110188
ins = ins->previous;
@@ -185,14 +263,21 @@ Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins) cons
185263
return optimizeRegisterType(arg);
186264
}
187265

188-
bool LLVMTypeAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const
266+
bool LLVMTypeAnalyzer::typesMatch(Compiler::StaticType a, Compiler::StaticType b) const
267+
{
268+
// Equal unknown types are not considered a match
269+
return (a == b) && (a != Compiler::StaticType::Unknown);
270+
}
271+
272+
bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const
189273
{
190274
// auto argIns = arg->instruction;
191275

192276
// TODO: Handle cross-variable dependencies
193277
/*if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem))
194278
return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/
195279

280+
return typesMatch(writeValueType(ins), expectedType);
196281
if (expectedType == Compiler::StaticType::Unknown) {
197282
// Equal unknown types are not considered a match
198283
return false;

src/engine/internal/llvm/llvmtypeanalyzer.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class LLVMTypeAnalyzer
1616
bool variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const;
1717

1818
private:
19+
Compiler::StaticType variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const;
20+
Compiler::StaticType variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const;
1921
bool variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const;
2022
LLVMInstruction *skipBranch(LLVMInstruction *pos) const;
2123
bool isLoopStart(LLVMInstruction *ins) const;
@@ -26,7 +28,8 @@ class LLVMTypeAnalyzer
2628

2729
Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
2830
Compiler::StaticType writeValueType(LLVMInstruction *ins) const;
29-
bool typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const;
31+
bool typesMatch(Compiler::StaticType a, Compiler::StaticType b) const;
32+
bool writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const;
3033
};
3134

3235
} // namespace libscratchcpp

0 commit comments

Comments
 (0)