Eliminate loading of uninitialized variables.
Bug swiftshader:27
Change-Id: I58259e00204550a397522fc26578c9f4d847f502
Reviewed-on: https://swiftshader-review.googlesource.com/8272
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 b528993..8ac70b1 100644
--- a/src/Reactor/Optimizer.cpp
+++ b/src/Reactor/Optimizer.cpp
@@ -30,19 +30,38 @@
private:
void analyzeUses(Ice::Cfg *function);
void eliminateUnusedAllocas();
+ void eliminateUnitializedLoads();
+
+ 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);
Ice::Cfg *function;
+ Ice::GlobalContext *context;
- std::map<Ice::Operand*, std::vector<Ice::Inst*>> uses;
+ struct Uses : std::vector<Ice::Inst*>
+ {
+ bool areOnlyLoadStore() const;
+ void insert(Ice::Operand *value, Ice::Inst *instruction);
+ void erase(Ice::Inst *instruction);
+
+ std::vector<Ice::Inst*> loads;
+ std::vector<Ice::Inst*> stores;
+ };
+
+ std::map<Ice::Operand*, Uses> uses;
};
void Optimizer::run(Ice::Cfg *function)
{
this->function = function;
+ this->context = function->getContext();
analyzeUses(function);
eliminateUnusedAllocas();
+ eliminateUnitializedLoads();
}
void Optimizer::eliminateUnusedAllocas()
@@ -65,6 +84,61 @@
}
}
+ void Optimizer::eliminateUnitializedLoads()
+ {
+ 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);
+ const auto &addressUses = addressEntry->second;
+
+ if(!addressUses.areOnlyLoadStore())
+ {
+ continue;
+ }
+
+ if(addressUses.stores.empty())
+ {
+ for(Ice::Inst *load : addressUses.loads)
+ {
+ Ice::Variable *loadData = load->getDest();
+
+ for(Ice::Inst *use : uses[loadData])
+ {
+ for(int i = 0; i < use->getSrcSize(); i++)
+ {
+ if(use->getSrc(i) == loadData)
+ {
+ auto *undef = context->getConstantUndef(loadData->getType());
+
+ use->replaceSource(i, undef);
+ }
+ }
+ }
+
+ uses.erase(loadData);
+
+ load->setDeleted();
+ }
+
+ alloca.setDeleted();
+ uses.erase(addressEntry);
+ }
+ }
+ }
+
void Optimizer::analyzeUses(Ice::Cfg *function)
{
uses.clear();
@@ -91,12 +165,144 @@
if(i == unique)
{
- uses[instruction.getSrc(i)].push_back(&instruction);
+ Ice::Operand *src = instruction.getSrc(i);
+ uses[src].insert(src, &instruction);
}
}
}
}
}
+
+ bool Optimizer::isLoad(const Ice::Inst &instruction)
+ {
+ if(llvm::isa<Ice::InstLoad>(&instruction))
+ {
+ return true;
+ }
+
+ if(auto intrinsicCall = llvm::dyn_cast<Ice::InstIntrinsicCall>(&instruction))
+ {
+ return intrinsicCall->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector;
+ }
+
+ return false;
+ }
+
+ bool Optimizer::isStore(const Ice::Inst &instruction)
+ {
+ if(llvm::isa<Ice::InstStore>(&instruction))
+ {
+ return true;
+ }
+
+ if(auto intrinsicCall = llvm::dyn_cast<Ice::InstIntrinsicCall>(&instruction))
+ {
+ return intrinsicCall->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector;
+ }
+
+ return false;
+ }
+
+ Ice::Operand *Optimizer::storeAddress(const Ice::Inst *instruction)
+ {
+ assert(isStore(*instruction));
+
+ if(auto *store = llvm::dyn_cast<Ice::InstStore>(instruction))
+ {
+ return store->getAddr();
+ }
+
+ if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
+ {
+ if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector)
+ {
+ return instrinsic->getSrc(2);
+ }
+ }
+
+ return nullptr;
+ }
+
+ Ice::Operand *Optimizer::loadAddress(const Ice::Inst *instruction)
+ {
+ assert(isLoad(*instruction));
+
+ if(auto *load = llvm::dyn_cast<Ice::InstLoad>(instruction))
+ {
+ return load->getSourceAddress();
+ }
+
+ if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction))
+ {
+ if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector)
+ {
+ return instrinsic->getSrc(1);
+ }
+ }
+
+ return nullptr;
+ }
+
+ bool Optimizer::Uses::areOnlyLoadStore() const
+ {
+ return size() == (loads.size() + stores.size());
+ }
+
+ void Optimizer::Uses::insert(Ice::Operand *value, Ice::Inst *instruction)
+ {
+ push_back(instruction);
+
+ if(isLoad(*instruction))
+ {
+ if(value == loadAddress(instruction))
+ {
+ loads.push_back(instruction);
+ }
+ }
+ else if(isStore(*instruction))
+ {
+ if(value == storeAddress(instruction))
+ {
+ stores.push_back(instruction);
+ }
+ }
+ }
+
+ void Optimizer::Uses::erase(Ice::Inst *instruction)
+ {
+ auto &uses = *this;
+
+ for(int i = 0; i < uses.size(); i++)
+ {
+ if(uses[i] == instruction)
+ {
+ uses[i] = back();
+ pop_back();
+
+ for(int i = 0; i < loads.size(); i++)
+ {
+ if(loads[i] == instruction)
+ {
+ loads[i] = loads.back();
+ loads.pop_back();
+ break;
+ }
+ }
+
+ for(int i = 0; i < stores.size(); i++)
+ {
+ if(stores[i] == instruction)
+ {
+ stores[i] = stores.back();
+ stores.pop_back();
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+ }
}
namespace sw