@@ -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+
85163bool 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 ;
0 commit comments