Skip to content

Commit d85fb86

Browse files
committed
LLVMCodeBuilder: Optimize variables and lists recursively used in loops
1 parent b55c4ac commit d85fb86

File tree

2 files changed

+32
-31
lines changed

2 files changed

+32
-31
lines changed

src/engine/internal/llvm/llvmcodebuilder.cpp

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -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)
22892287
bool 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);

src/engine/internal/llvm/llvmcodebuilder.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@ class LLVMCodeBuilder : public ICodeBuilder
150150
void reloadLists();
151151
void updateListDataPtr(const LLVMListPtr &listPtr);
152152
bool isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType) const;
153-
bool isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType, std::unordered_set<LLVMInstruction *> &processed) const;
154-
bool isVarOrListWriteResultTypeSafe(std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set<LLVMInstruction *> &processed) const;
153+
bool isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType, std::unordered_set<LLVMInstruction *> &log, int &c) const;
154+
bool isVarOrListWriteResultTypeSafe(std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set<LLVMInstruction *> &log, int &c) const;
155155

156156
LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args);
157157
LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes = {}, const Compiler::Args &args = {});

0 commit comments

Comments
 (0)