Eliminate loads following a single store.
Bug swiftshader:27
Change-Id: I11238decf114381126a7465c462d918a3f16b0d8
Reviewed-on: https://swiftshader-review.googlesource.com/8273
Tested-by: Nicolas Capens <capn@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/Reactor/Optimizer.cpp b/src/Reactor/Optimizer.cpp
index 8ac70b1..a3b328e 100644
--- a/src/Reactor/Optimizer.cpp
+++ b/src/Reactor/Optimizer.cpp
@@ -31,11 +31,16 @@
void analyzeUses(Ice::Cfg *function);
void eliminateUnusedAllocas();
void eliminateUnitializedLoads();
+ void eliminateLoadsFollowingSingleStore();
+
+ void replace(Ice::Inst *instruction, Ice::Operand *newValue);
+ void deleteInstruction(Ice::Inst *instruction);
static bool isLoad(const Ice::Inst &instruction);
static bool isStore(const Ice::Inst &instruction);
static Ice::Operand *storeAddress(const Ice::Inst *instruction);
static Ice::Operand *loadAddress(const Ice::Inst *instruction);
+ static Ice::Operand *storeData(const Ice::Inst *instruction);
Ice::Cfg *function;
Ice::GlobalContext *context;
@@ -51,6 +56,8 @@
};
std::map<Ice::Operand*, Uses> uses;
+ std::map<Ice::Inst*, Ice::CfgNode*> node;
+ std::map<Ice::Variable*, Ice::Inst*> definition;
};
void Optimizer::run(Ice::Cfg *function)
@@ -62,6 +69,7 @@
eliminateUnusedAllocas();
eliminateUnitializedLoads();
+ eliminateLoadsFollowingSingleStore();
}
void Optimizer::eliminateUnusedAllocas()
@@ -139,9 +147,107 @@
}
}
+ void Optimizer::eliminateLoadsFollowingSingleStore()
+ {
+ Ice::CfgNode *entryBlock = function->getEntryNode();
+
+ for(Ice::Inst &alloca : entryBlock->getInsts())
+ {
+ if(alloca.isDeleted())
+ {
+ continue;
+ }
+
+ if(!llvm::isa<Ice::InstAlloca>(alloca))
+ {
+ return; // Allocas are all at the top
+ }
+
+ Ice::Operand *address = alloca.getDest();
+ const auto &addressEntry = uses.find(address);
+ auto &addressUses = addressEntry->second;
+
+ if(!addressUses.areOnlyLoadStore())
+ {
+ continue;
+ }
+
+ if(addressUses.stores.size() == 1)
+ {
+ Ice::Inst *store = addressUses.stores[0];
+ Ice::Operand *storeValue = storeData(store);
+
+ for(Ice::Inst *load = &*++store->getIterator(), *next = nullptr; load != next; next = load, load = &*++store->getIterator())
+ {
+ if(load->isDeleted() || !isLoad(*load))
+ {
+ continue;
+ }
+
+ if(loadAddress(load) != address)
+ {
+ continue;
+ }
+
+ replace(load, storeValue);
+
+ for(int i = 0; i < addressUses.loads.size(); i++)
+ {
+ if(addressUses.loads[i] == load)
+ {
+ addressUses.loads[i] = addressUses.loads.back();
+ addressUses.loads.pop_back();
+ break;
+ }
+ }
+
+ for(int i = 0; i < addressUses.size(); i++)
+ {
+ if(addressUses[i] == load)
+ {
+ addressUses[i] = addressUses.back();
+ addressUses.pop_back();
+ break;
+ }
+ }
+
+ if(addressUses.size() == 1)
+ {
+ assert(addressUses[0] == store);
+
+ alloca.setDeleted();
+ store->setDeleted();
+ uses.erase(address);
+
+ auto &valueUses = uses[storeValue];
+
+ for(int i = 0; i < valueUses.size(); i++)
+ {
+ if(valueUses[i] == store)
+ {
+ valueUses[i] = valueUses.back();
+ valueUses.pop_back();
+ break;
+ }
+ }
+
+ if(valueUses.empty())
+ {
+ uses.erase(storeValue);
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
void Optimizer::analyzeUses(Ice::Cfg *function)
{
uses.clear();
+ node.clear();
+ definition.clear();
for(Ice::CfgNode *basicBlock : function->getNodes())
{
@@ -152,6 +258,9 @@
continue;
}
+ node[&instruction] = basicBlock;
+ definition[instruction.getDest()] = &instruction;
+
for(int i = 0; i < instruction.getSrcSize(); i++)
{
int unique = 0;
@@ -173,6 +282,69 @@
}
}
+ void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue)
+ {
+ Ice::Variable *oldValue = instruction->getDest();
+
+ if(!newValue)
+ {
+ newValue = context->getConstantUndef(oldValue->getType());
+ }
+
+ for(Ice::Inst *use : uses[oldValue])
+ {
+ assert(!use->isDeleted()); // Should have been removed from uses already
+
+ for(int i = 0; i < use->getSrcSize(); i++)
+ {
+ if(use->getSrc(i) == oldValue)
+ {
+ use->replaceSource(i, newValue);
+ }
+ }
+
+ uses[newValue].insert(newValue, use);
+ }
+
+ uses.erase(oldValue);
+
+ deleteInstruction(instruction);
+ }
+
+ void Optimizer::deleteInstruction(Ice::Inst *instruction)
+ {
+ if(instruction->isDeleted())
+ {
+ return;
+ }
+
+ instruction->setDeleted();
+
+ for(int i = 0; i < instruction->getSrcSize(); i++)
+ {
+ Ice::Operand *src = instruction->getSrc(i);
+
+ const auto &srcEntry = uses.find(src);
+
+ if(srcEntry != uses.end())
+ {
+ auto &srcUses = srcEntry->second;
+
+ srcUses.erase(instruction);
+
+ if(srcUses.empty())
+ {
+ uses.erase(srcEntry);
+
+ if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src))
+ {
+ deleteInstruction(definition[var]);
+ }
+ }
+ }
+ }
+ }
+
bool Optimizer::isLoad(const Ice::Inst &instruction)
{
if(llvm::isa<Ice::InstLoad>(&instruction))
@@ -243,6 +415,26 @@
return nullptr;
}
+ Ice::Operand *Optimizer::storeData(const Ice::Inst *instruction)
+ {
+ assert(isStore(*instruction));
+
+ if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
+ {
+ return store->getData();
+ }
+
+ if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
+ {
+ if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
+ {
+ return instrinsic->getSrc(1);
+ }
+ }
+
+ return nullptr;
+ }
+
bool Optimizer::Uses::areOnlyLoadStore() const
{
return size() == (loads.size() + stores.size());