@@ -728,7 +728,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
728728 Compiler::StaticType type = optimizeRegisterType (arg.second );
729729 LLVMListPtr &listPtr = m_listPtrs[step.workList ];
730730
731- const bool safe = isVarOrListTypeSafe (insPtr, listPtr.type );
732731 auto &typeMap = m_scopeLists.back ();
733732
734733 if (typeMap.find (&listPtr) == typeMap.cend ()) {
@@ -739,7 +738,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
739738 typeMap[&listPtr] = listPtr.type ;
740739 }
741740
742- if (!safe )
741+ if (!isVarOrListTypeSafe (insPtr, listPtr. type ) )
743742 listPtr.type = Compiler::StaticType::Unknown;
744743
745744 // Check if enough space is allocated
@@ -777,7 +776,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
777776 Compiler::StaticType type = optimizeRegisterType (valueArg.second );
778777 LLVMListPtr &listPtr = m_listPtrs[step.workList ];
779778
780- const bool safe = isVarOrListTypeSafe (insPtr, listPtr.type );
781779 auto &typeMap = m_scopeLists.back ();
782780
783781 if (typeMap.find (&listPtr) == typeMap.cend ()) {
@@ -788,7 +786,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
788786 typeMap[&listPtr] = listPtr.type ;
789787 }
790788
791- if (!safe )
789+ if (!isVarOrListTypeSafe (insPtr, listPtr. type ) )
792790 listPtr.type = Compiler::StaticType::Unknown;
793791
794792 llvm::Value *oldAllocatedSize = m_builder.CreateLoad (m_builder.getInt64Ty (), listPtr.allocatedSizePtr );
@@ -2289,10 +2287,11 @@ void LLVMCodeBuilder::updateListDataPtr(const LLVMListPtr &listPtr)
22892287bool LLVMCodeBuilder::isVarOrListTypeSafe (std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType) const
22902288{
22912289 std::unordered_set<LLVMInstruction *> processed;
2292- return isVarOrListTypeSafe (ins, expectedType, processed);
2290+ int counter = 0 ;
2291+ return isVarOrListTypeSafe (ins, expectedType, processed, counter);
22932292}
22942293
2295- bool LLVMCodeBuilder::isVarOrListTypeSafe (std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType, std::unordered_set<LLVMInstruction *> &processed ) const
2294+ bool LLVMCodeBuilder::isVarOrListTypeSafe (std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType, std::unordered_set<LLVMInstruction *> &log, int &c ) const
22962295{
22972296 /*
22982297 * The main part of the loop type analyzer.
@@ -2318,22 +2317,20 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins,
23182317
23192318 /*
23202319 * If we are processing something that has been already
2321- * processed, give up to avoid infinite recursion.
2322- *
2323- * This can happen in edge cases like this:
2324- * var = var
2320+ * processed, it means there's a case like this:
2321+ * x = x
23252322 *
23262323 * or this:
23272324 * x = y
2325+ * ...
23282326 * y = x
23292327 *
2330- * This code isn't considered valid, so don't bother
2331- * optimizing.
2328+ * Increment counter to ignore last n write operations.
23322329 */
2333- if (processed .find (ins.get ()) != processed .cend ())
2334- return false ;
2335-
2336- processed .insert (ins.get ());
2330+ if (log .find (ins.get ()) != log .cend ())
2331+ c++ ;
2332+ else
2333+ log .insert (ins.get ());
23372334
23382335 assert (std::find (m_instructions.begin (), m_instructions.end (), ins) != m_instructions.end ());
23392336 const LLVMVariablePtr *varPtr = ins->workVariable ? &m_variablePtrs.at (ins->workVariable ) : nullptr ;
@@ -2388,32 +2385,34 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins,
23882385 // If there was a write operation before this instruction (in this, parent or child scope), check it
23892386 if (parentScope) {
23902387 if (parentScope == scope)
2391- return isVarOrListWriteResultTypeSafe (write, expectedType, true , processed );
2388+ return isVarOrListWriteResultTypeSafe (write, expectedType, true , log, c );
23922389 else
2393- return isVarOrListTypeSafe (write, expectedType, processed );
2390+ return isVarOrListTypeSafe (write, expectedType, log, c );
23942391 }
23952392 }
23962393 }
23972394
23982395 const auto &loopWrites = varPtr ? varPtr->loopVariableWrites : listPtr->loopListWrites ;
23992396
2400- // Get last write operation
2401- write = nullptr ;
2402-
24032397 // Find root loop scope
24042398 auto checkScope = scope;
24052399
24062400 while (checkScope->parentScope ) {
24072401 checkScope = checkScope->parentScope ;
24082402 }
24092403
2410- // Find last loop scope (may be a parent or child scope)
2404+ // Find n-th last write operation based on counter (may be in a parent or child scope)
2405+ std::vector<std::shared_ptr<LLVMInstruction>> lastWrites;
2406+
24112407 while (checkScope) {
24122408 auto it = loopWrites.find (checkScope);
24132409
24142410 if (it != loopWrites.cend ()) {
24152411 assert (!it->second .empty ());
2416- write = it->second .back ();
2412+ const auto &writes = it->second ;
2413+
2414+ for (auto w : writes)
2415+ lastWrites.push_back (w);
24172416 }
24182417
24192418 if (checkScope->childScopes .empty ())
@@ -2422,22 +2421,24 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins,
24222421 checkScope = checkScope->childScopes .back ();
24232422 }
24242423
2425- // If there aren't any write operations, we're safe
2426- if (!write )
2424+ // If there aren't any write operations or all of them are ignored , we're safe
2425+ if (c >= lastWrites. size () )
24272426 return true ;
24282427
2428+ write = lastWrites[lastWrites.size () - c - 1 ]; // Ignore last c writes
2429+
24292430 bool safe = true ;
24302431
24312432 if (VAR_LIST_READ_INSTRUCTIONS.find (ins->type ) == VAR_LIST_READ_INSTRUCTIONS.cend ()) // write
2432- safe = isVarOrListWriteResultTypeSafe (ins, expectedType, false , processed );
2433+ safe = isVarOrListWriteResultTypeSafe (ins, expectedType, false , log, c );
24332434
24342435 if (safe)
2435- return isVarOrListWriteResultTypeSafe (write, expectedType, false , processed );
2436+ return isVarOrListWriteResultTypeSafe (write, expectedType, false , log, c );
24362437 else
24372438 return false ;
24382439}
24392440
2440- bool LLVMCodeBuilder::isVarOrListWriteResultTypeSafe (std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set<LLVMInstruction *> &processed )
2441+ bool LLVMCodeBuilder::isVarOrListWriteResultTypeSafe (std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set<LLVMInstruction *> &log, int &c )
24412442 const
24422443{
24432444 const LLVMVariablePtr *varPtr = ins->workVariable ? &m_variablePtrs.at (ins->workVariable ) : nullptr ;
@@ -2449,7 +2450,7 @@ bool LLVMCodeBuilder::isVarOrListWriteResultTypeSafe(std::shared_ptr<LLVMInstruc
24492450 auto argIns = arg->instruction ;
24502451
24512452 if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem))
2452- return isVarOrListTypeSafe (argIns, expectedType, processed );
2453+ return isVarOrListTypeSafe (argIns, expectedType, log, c );
24532454
24542455 // Check written type
24552456 const bool typeMatches = (optimizeRegisterType (arg) == expectedType);
0 commit comments