@@ -9,10 +9,39 @@ static const std::unordered_set<LLVMInstruction::Type>
99 BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop };
1010
1111Compiler::StaticType LLVMTypeAnalyzer::variableType (Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const
12+ {
13+ InstructionSet visitedInstructions;
14+ return variableType (var, pos, previousType, visitedInstructions);
15+ }
16+
17+ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch (Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const
18+ {
19+ InstructionSet visitedInstructions;
20+ return variableTypeAfterBranch (var, start, previousType, visitedInstructions);
21+ }
22+
23+ Compiler::StaticType LLVMTypeAnalyzer::variableType (Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const
1224{
1325 if (!var || !pos)
1426 return Compiler::StaticType::Unknown;
1527
28+ /*
29+ * If the given instruction has already been processed,
30+ * it means there's a case like this:
31+ * x = x
32+ *
33+ * or this:
34+ * x = y
35+ * ...
36+ * y = x
37+ */
38+ if (visitedInstructions.find (pos) != visitedInstructions.cend ()) {
39+ // Circular dependencies are rare (and bad) so don't optimize them
40+ return Compiler::StaticType::Unknown;
41+ }
42+
43+ visitedInstructions.insert (pos);
44+
1645 // Check the last write operation before the instruction
1746 LLVMInstruction *ins = pos;
1847 LLVMInstruction *write = nullptr ;
@@ -35,7 +64,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi
3564 firstElseBranch = ins;
3665 ins = skipBranch (ins);
3766 continue ;
38- } else if (isVariableWrite (ins, var)) {
67+ } else if (isVariableWrite (ins, var) && ! isWriteNoOp (ins) ) {
3968 if (level <= 0 ) { // ignore nested branches (they're handled by the branch analyzer)
4069 write = ins;
4170 break ;
@@ -50,14 +79,14 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi
5079 bool ignoreWriteAfterPos = (isIfStart (firstBranch) && firstBranch == ourBranch);
5180
5281 if (write)
53- previousType = writeValueType (write); // write operation overrides previous type
82+ previousType = writeValueType (write, visitedInstructions ); // write operation overrides previous type
5483
5584 Compiler::StaticType firstBranchType = previousType;
5685 Compiler::StaticType elseBranchType = previousType;
5786
5887 if (!ignoreWriteAfterPos) {
59- firstBranchType = variableTypeAfterBranch (var, firstBranch, previousType);
60- elseBranchType = variableTypeAfterBranch (var, firstElseBranch, previousType);
88+ firstBranchType = variableTypeAfterBranch (var, firstBranch, previousType, visitedInstructions );
89+ elseBranchType = variableTypeAfterBranch (var, firstElseBranch, previousType, visitedInstructions );
6190 }
6291
6392 if (typesMatch (firstBranchType, elseBranchType))
@@ -66,14 +95,14 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi
6695 return Compiler::StaticType::Unknown;
6796 } else if (write) {
6897 // There wasn't any branch found, so we can just check the last write operation
69- return writeValueType (write);
98+ return writeValueType (write, visitedInstructions );
7099 }
71100
72101 // No write operation found
73102 return previousType;
74103}
75104
76- Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch (Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const
105+ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch (Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions ) const
77106{
78107 if (!var || !start)
79108 return previousType;
@@ -102,10 +131,10 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL
102131
103132 // Process the branch from end
104133 bool write = false ; // only used internally (the compiler doesn't need this)
105- return variableTypeAfterBranchFromEnd (var, ins, previousType, write);
134+ return variableTypeAfterBranchFromEnd (var, ins, previousType, write, visitedInstructions );
106135}
107136
108- Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd (Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const
137+ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd (Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions ) const
109138{
110139 // Find the last write instruction
111140 LLVMInstruction *ins = end->previous ;
@@ -114,7 +143,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
114143 while (ins && !isLoopStart (ins) && !isIfStart (ins)) {
115144 if (isLoopEnd (ins) || isIfEnd (ins) || isElse (ins)) {
116145 // Process the nested loop or if statement
117- Compiler::StaticType ret = variableTypeAfterBranchFromEnd (var, ins, previousType, write);
146+ Compiler::StaticType ret = variableTypeAfterBranchFromEnd (var, ins, previousType, write, visitedInstructions );
118147
119148 if (typesMatch (ret, previousType)) {
120149 if (write)
@@ -126,7 +155,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
126155
127156 if (isElse (ins)) {
128157 // Process if branch (the else branch is already processed)
129- ret = variableTypeAfterBranchFromEnd (var, ins, previousType, write);
158+ ret = variableTypeAfterBranchFromEnd (var, ins, previousType, write, visitedInstructions );
130159
131160 if (typesMatch (ret, previousType)) {
132161 if (write) {
@@ -140,9 +169,9 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
140169
141170 ins = skipBranch (ins);
142171 }
143- } else if (isVariableWrite (ins, var)) {
172+ } else if (isVariableWrite (ins, var) && ! isWriteNoOp (ins) ) {
144173 // Variable write instruction
145- Compiler::StaticType writeType = writeValueType (ins);
174+ Compiler::StaticType writeType = writeValueType (ins, visitedInstructions );
146175 write = true ;
147176
148177 if (typesMatch (writeType, previousType))
@@ -208,6 +237,11 @@ bool LLVMTypeAnalyzer::isIfEnd(LLVMInstruction *ins) const
208237 return (ins->type == LLVMInstruction::Type::EndIf);
209238}
210239
240+ bool LLVMTypeAnalyzer::isVariableRead (LLVMInstruction *ins) const
241+ {
242+ return (ins->type == LLVMInstruction::Type::ReadVariable);
243+ }
244+
211245bool LLVMTypeAnalyzer::isVariableWrite (LLVMInstruction *ins, Variable *var) const
212246{
213247 return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == var);
@@ -227,12 +261,40 @@ Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) c
227261 return ret;
228262}
229263
230- Compiler::StaticType LLVMTypeAnalyzer::writeValueType (LLVMInstruction *ins) const
264+ bool LLVMTypeAnalyzer::isWriteNoOp (LLVMInstruction *ins) const
231265{
232266 assert (ins);
233267 assert (!ins->args .empty ());
234268 const auto arg = ins->args .back ().second ; // value is always the last argument in variable/list write instructions
235- return optimizeRegisterType (arg);
269+
270+ if (arg->instruction ) {
271+ // TODO: Handle list item
272+ if (isVariableRead (arg->instruction .get ())) {
273+ // Self-assignment is a no-op
274+ return (ins->workVariable == arg->instruction ->workVariable );
275+ }
276+ }
277+
278+ return false ;
279+ }
280+
281+ Compiler::StaticType LLVMTypeAnalyzer::writeValueType (LLVMInstruction *ins, InstructionSet &visitedInstructions) const
282+ {
283+ assert (ins);
284+ assert (!ins->args .empty ());
285+ const auto arg = ins->args .back ().second ; // value is always the last argument in variable/list write instructions
286+
287+ if (arg->instruction ) {
288+ // TODO: Handle list item
289+ if (isVariableRead (arg->instruction .get ())) {
290+ // If this is a variable read instruction, recursively get the variable type
291+ return variableType (arg->instruction ->workVariable , arg->instruction .get (), Compiler::StaticType::Unknown, visitedInstructions);
292+ } else {
293+ // TODO: Use the instruction return register
294+ return optimizeRegisterType (arg);
295+ }
296+ } else
297+ return optimizeRegisterType (arg);
236298}
237299
238300bool LLVMTypeAnalyzer::typesMatch (Compiler::StaticType a, Compiler::StaticType b) const
@@ -241,13 +303,7 @@ bool LLVMTypeAnalyzer::typesMatch(Compiler::StaticType a, Compiler::StaticType b
241303 return (a == b) && (a != Compiler::StaticType::Unknown);
242304}
243305
244- bool LLVMTypeAnalyzer::writeTypesMatch (LLVMInstruction *ins, Compiler::StaticType expectedType) const
306+ bool LLVMTypeAnalyzer::writeTypesMatch (LLVMInstruction *ins, Compiler::StaticType expectedType, InstructionSet &visitedInstructions ) const
245307{
246- // auto argIns = arg->instruction;
247-
248- // TODO: Handle cross-variable dependencies
249- /* if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem))
250- return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/
251-
252- return typesMatch (writeValueType (ins), expectedType);
308+ return typesMatch (writeValueType (ins, visitedInstructions), expectedType);
253309}
0 commit comments