OSDN Git Service

Eliminate loading of uninitialized variables.
authorNicolas Capens <capn@google.com>
Mon, 12 Dec 2016 18:08:06 +0000 (13:08 -0500)
committerNicolas Capens <capn@google.com>
Tue, 13 Dec 2016 16:42:47 +0000 (16:42 +0000)
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>
src/Reactor/Main.cpp
src/Reactor/Optimizer.cpp

index 3adb638..ae23773 100644 (file)
@@ -73,6 +73,43 @@ TEST(SubzeroReactorTest, Sample)
        delete routine;
 }
 
+TEST(SubzeroReactorTest, Uninitialized)
+{
+       Routine *routine = nullptr;
+
+       {
+               Function<Int()> function;
+               {
+                       Int a;
+                       Int z = 4;
+                       Int q;
+                       Int c;
+                       Int p;
+                       Bool b;
+
+                       q += q;
+
+                       If(b)
+                       {
+                               c = p;
+                       }
+   
+                       Return(a + z + q + c);
+               }
+
+               routine = function(L"one");
+
+               if(routine)
+               {
+                       int (*callable)() = (int(*)())routine->getEntry();
+                       int result = callable();
+                       EXPECT_EQ(result, result);   // Anything is fine, just don't crash
+               }
+       }
+
+       delete routine;
+}
+
 TEST(SubzeroReactorTest, SubVectorLoadStore)
 {
        Routine *routine = nullptr;
index b528993..8ac70b1 100644 (file)
@@ -30,19 +30,38 @@ namespace
        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;
+
+               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*, std::vector<Ice::Inst*>> uses;
+               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 @@ namespace
                }
        }
 
+       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 @@ namespace
 
                                        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