Optimize stores in a single basic block.

Bug swiftshader:27

Change-Id: Ia5f7da431902c3e87aab47b1dd388e05ced74cd3
Reviewed-on: https://swiftshader-review.googlesource.com/8274
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 a3b328e..39de5f0 100644
--- a/src/Reactor/Optimizer.cpp
+++ b/src/Reactor/Optimizer.cpp
@@ -32,6 +32,7 @@
 		void eliminateUnusedAllocas();
 		void eliminateUnitializedLoads();
 		void eliminateLoadsFollowingSingleStore();
+		void optimizeStoresInSingleBasicBlock();
 
 		void replace(Ice::Inst *instruction, Ice::Operand *newValue);
 		void deleteInstruction(Ice::Inst *instruction);
@@ -70,6 +71,7 @@
 		eliminateUnusedAllocas();
 		eliminateUnitializedLoads();
 		eliminateLoadsFollowingSingleStore();
+		optimizeStoresInSingleBasicBlock();
 	}
 
 	void Optimizer::eliminateUnusedAllocas()
@@ -243,6 +245,88 @@
 		}
 	}
 
+	void Optimizer::optimizeStoresInSingleBasicBlock()
+	{
+		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;
+			}
+
+			Ice::CfgNode *singleBasicBlock = node[addressUses.stores[0]];
+
+			for(int i = 1; i < addressUses.stores.size(); i++)
+			{
+				Ice::Inst *store = addressUses.stores[i];
+				if(node[store] != singleBasicBlock)
+				{
+					singleBasicBlock = nullptr;
+					break;
+				}
+			}
+
+			if(singleBasicBlock)
+			{
+				auto &insts = singleBasicBlock->getInsts();
+				Ice::Inst *store = nullptr;
+				Ice::Operand *storeValue = nullptr;
+
+				for(Ice::Inst &inst : insts)
+				{
+					if(inst.isDeleted())
+					{
+						continue;
+					}
+
+					if(isStore(inst))
+					{
+						if(storeAddress(&inst) != address)
+						{
+							continue;
+						}
+
+						// New store found. If we had a previous one, eliminate it.
+						if(store)
+						{
+							deleteInstruction(store);
+						}
+
+						store = &inst;
+						storeValue = storeData(store);
+					}
+					else if(isLoad(inst))
+					{
+						Ice::Inst *load = &inst;
+
+						if(loadAddress(load) != address)
+						{
+							continue;
+						}
+
+						replace(load, storeValue);
+					}
+				}
+			}
+		}
+	}
+
 	void Optimizer::analyzeUses(Ice::Cfg *function)
 	{
 		uses.clear();