|  | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //    http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #include "Optimizer.hpp" | 
|  |  | 
|  | #include "src/IceCfg.h" | 
|  | #include "src/IceCfgNode.h" | 
|  |  | 
|  | #include <vector> | 
|  |  | 
|  | namespace | 
|  | { | 
|  | class Optimizer | 
|  | { | 
|  | public: | 
|  | void run(Ice::Cfg *function); | 
|  |  | 
|  | private: | 
|  | void analyzeUses(Ice::Cfg *function); | 
|  | void eliminateDeadCode(); | 
|  | void eliminateUnitializedLoads(); | 
|  | void eliminateLoadsFollowingSingleStore(); | 
|  | void optimizeStoresInSingleBasicBlock(); | 
|  |  | 
|  | void replace(Ice::Inst *instruction, Ice::Operand *newValue); | 
|  | void deleteInstruction(Ice::Inst *instruction); | 
|  | bool isDead(Ice::Inst *instruction); | 
|  |  | 
|  | static const Ice::InstIntrinsicCall *asLoadSubVector(const Ice::Inst *instruction); | 
|  | static const Ice::InstIntrinsicCall *asStoreSubVector(const 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); | 
|  | static std::size_t storeSize(const Ice::Inst *instruction); | 
|  | static bool loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store); | 
|  |  | 
|  | 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; | 
|  | }; | 
|  |  | 
|  | struct LoadStoreInst | 
|  | { | 
|  | LoadStoreInst(Ice::Inst* inst, bool isStore) | 
|  | : inst(inst), | 
|  | address(isStore ? storeAddress(inst) : loadAddress(inst)), | 
|  | isStore(isStore) | 
|  | { | 
|  | } | 
|  |  | 
|  | Ice::Inst* inst; | 
|  | Ice::Operand *address; | 
|  | bool isStore; | 
|  | }; | 
|  |  | 
|  | Optimizer::Uses* getUses(Ice::Operand*); | 
|  | void setUses(Ice::Operand*, Optimizer::Uses*); | 
|  | bool hasUses(Ice::Operand*) const; | 
|  |  | 
|  | Ice::CfgNode* getNode(Ice::Inst*); | 
|  | void setNode(Ice::Inst*, Ice::CfgNode*); | 
|  |  | 
|  | Ice::Inst* getDefinition(Ice::Variable*); | 
|  | void setDefinition(Ice::Variable*, Ice::Inst*); | 
|  |  | 
|  | const std::vector<LoadStoreInst>& getLoadStoreInsts(Ice::CfgNode*); | 
|  | void setLoadStoreInsts(Ice::CfgNode*, std::vector<LoadStoreInst>*); | 
|  | bool hasLoadStoreInsts(Ice::CfgNode* node) const; | 
|  |  | 
|  | std::vector<Optimizer::Uses*> allocatedUses; | 
|  | }; | 
|  |  | 
|  | void Optimizer::run(Ice::Cfg *function) | 
|  | { | 
|  | this->function = function; | 
|  | this->context = function->getContext(); | 
|  |  | 
|  | analyzeUses(function); | 
|  |  | 
|  | eliminateDeadCode(); | 
|  | eliminateUnitializedLoads(); | 
|  | eliminateLoadsFollowingSingleStore(); | 
|  | optimizeStoresInSingleBasicBlock(); | 
|  | eliminateDeadCode(); | 
|  |  | 
|  | for(auto uses : allocatedUses) | 
|  | { | 
|  | delete uses; | 
|  | } | 
|  | allocatedUses.clear(); | 
|  | } | 
|  |  | 
|  | void Optimizer::eliminateDeadCode() | 
|  | { | 
|  | bool modified; | 
|  | do | 
|  | { | 
|  | modified = false; | 
|  | for(Ice::CfgNode *basicBlock : function->getNodes()) | 
|  | { | 
|  | for(Ice::Inst &inst : Ice::reverse_range(basicBlock->getInsts())) | 
|  | { | 
|  | if(inst.isDeleted()) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if(isDead(&inst)) | 
|  | { | 
|  | deleteInstruction(&inst); | 
|  | modified = true; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | while(modified); | 
|  | } | 
|  |  | 
|  | void Optimizer::eliminateUnitializedLoads() | 
|  | { | 
|  | Ice::CfgNode *entryBlock = function->getEntryNode(); | 
|  |  | 
|  | for(Ice::Inst &alloca : entryBlock->getInsts()) | 
|  | { | 
|  | if(alloca.isDeleted()) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if(!llvm::isa<Ice::InstAlloca>(alloca)) | 
|  | { | 
|  | break;   // Allocas are all at the top | 
|  | } | 
|  |  | 
|  | Ice::Operand *address = alloca.getDest(); | 
|  |  | 
|  | if(!hasUses(address)) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | const auto &addressUses = *getUses(address); | 
|  |  | 
|  | if(!addressUses.areOnlyLoadStore()) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if(addressUses.stores.empty()) | 
|  | { | 
|  | for(Ice::Inst *load : addressUses.loads) | 
|  | { | 
|  | Ice::Variable *loadData = load->getDest(); | 
|  |  | 
|  | if(hasUses(loadData)) | 
|  | { | 
|  | for(Ice::Inst *use : *getUses(loadData)) | 
|  | { | 
|  | for(Ice::SizeT i = 0; i < use->getSrcSize(); i++) | 
|  | { | 
|  | if(use->getSrc(i) == loadData) | 
|  | { | 
|  | auto *undef = context->getConstantUndef(loadData->getType()); | 
|  |  | 
|  | use->replaceSource(i, undef); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | setUses(loadData, nullptr); | 
|  | } | 
|  |  | 
|  | load->setDeleted(); | 
|  | } | 
|  |  | 
|  | alloca.setDeleted(); | 
|  | setUses(address, nullptr); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void Optimizer::eliminateLoadsFollowingSingleStore() | 
|  | { | 
|  | Ice::CfgNode *entryBlock = function->getEntryNode(); | 
|  |  | 
|  | for(Ice::Inst &alloca : entryBlock->getInsts()) | 
|  | { | 
|  | if(alloca.isDeleted()) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if(!llvm::isa<Ice::InstAlloca>(alloca)) | 
|  | { | 
|  | break;   // Allocas are all at the top | 
|  | } | 
|  |  | 
|  | Ice::Operand *address = alloca.getDest(); | 
|  |  | 
|  | if(!hasUses(address)) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | auto &addressUses = *getUses(address); | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | if(!loadTypeMatchesStore(load, store)) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | replace(load, storeValue); | 
|  |  | 
|  | for(size_t i = 0; i < addressUses.loads.size(); i++) | 
|  | { | 
|  | if(addressUses.loads[i] == load) | 
|  | { | 
|  | addressUses.loads[i] = addressUses.loads.back(); | 
|  | addressUses.loads.pop_back(); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | for(size_t 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(); | 
|  | setUses(address, nullptr); | 
|  |  | 
|  | if(hasUses(storeValue)) | 
|  | { | 
|  | auto &valueUses = *getUses(storeValue); | 
|  |  | 
|  | for(size_t i = 0; i < valueUses.size(); i++) | 
|  | { | 
|  | if(valueUses[i] == store) | 
|  | { | 
|  | valueUses[i] = valueUses.back(); | 
|  | valueUses.pop_back(); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(valueUses.empty()) | 
|  | { | 
|  | setUses(storeValue, nullptr); | 
|  | } | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void Optimizer::optimizeStoresInSingleBasicBlock() | 
|  | { | 
|  | Ice::CfgNode *entryBlock = function->getEntryNode(); | 
|  |  | 
|  | std::vector<std::vector<LoadStoreInst>* > allocatedVectors; | 
|  |  | 
|  | for(Ice::Inst &alloca : entryBlock->getInsts()) | 
|  | { | 
|  | if(alloca.isDeleted()) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if(!llvm::isa<Ice::InstAlloca>(alloca)) | 
|  | { | 
|  | break;   // Allocas are all at the top | 
|  | } | 
|  |  | 
|  | Ice::Operand *address = alloca.getDest(); | 
|  |  | 
|  | if(!hasUses(address)) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | const auto &addressUses = *getUses(address); | 
|  |  | 
|  | if(!addressUses.areOnlyLoadStore()) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | Ice::CfgNode *singleBasicBlock = getNode(addressUses.stores[0]); | 
|  |  | 
|  | for(size_t i = 1; i < addressUses.stores.size(); i++) | 
|  | { | 
|  | Ice::Inst *store = addressUses.stores[i]; | 
|  | if(getNode(store) != singleBasicBlock) | 
|  | { | 
|  | singleBasicBlock = nullptr; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(singleBasicBlock) | 
|  | { | 
|  | if(!hasLoadStoreInsts(singleBasicBlock)) | 
|  | { | 
|  | std::vector<LoadStoreInst>* loadStoreInstVector = new std::vector<LoadStoreInst>(); | 
|  | setLoadStoreInsts(singleBasicBlock, loadStoreInstVector); | 
|  | allocatedVectors.push_back(loadStoreInstVector); | 
|  | for(Ice::Inst &inst : singleBasicBlock->getInsts()) | 
|  | { | 
|  | if(inst.isDeleted()) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | bool isStoreInst = isStore(inst); | 
|  | bool isLoadInst = isLoad(inst); | 
|  |  | 
|  | if(isStoreInst || isLoadInst) | 
|  | { | 
|  | loadStoreInstVector->push_back(LoadStoreInst(&inst, isStoreInst)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | Ice::Inst *store = nullptr; | 
|  | Ice::Operand *storeValue = nullptr; | 
|  | bool unmatchedLoads = false; | 
|  |  | 
|  | for (auto& loadStoreInst : getLoadStoreInsts(singleBasicBlock)) | 
|  | { | 
|  | Ice::Inst* inst = loadStoreInst.inst; | 
|  |  | 
|  | if((loadStoreInst.address != address) || inst->isDeleted()) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if(loadStoreInst.isStore) | 
|  | { | 
|  | // New store found. If we had a previous one, try to eliminate it. | 
|  | if(store && !unmatchedLoads) | 
|  | { | 
|  | // If the previous store is wider than the new one, we can't eliminate it | 
|  | // because there could be a wide load reading its non-overwritten data. | 
|  | if(storeSize(inst) >= storeSize(store)) | 
|  | { | 
|  | deleteInstruction(store); | 
|  | } | 
|  | } | 
|  |  | 
|  | store = inst; | 
|  | storeValue = storeData(store); | 
|  | unmatchedLoads = false; | 
|  | } | 
|  | else | 
|  | { | 
|  | if(!loadTypeMatchesStore(inst, store)) | 
|  | { | 
|  | unmatchedLoads = true; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | replace(inst, storeValue); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | for(auto loadStoreInstVector : allocatedVectors) | 
|  | { | 
|  | delete loadStoreInstVector; | 
|  | } | 
|  | } | 
|  |  | 
|  | void Optimizer::analyzeUses(Ice::Cfg *function) | 
|  | { | 
|  | for(Ice::CfgNode *basicBlock : function->getNodes()) | 
|  | { | 
|  | for(Ice::Inst &instruction : basicBlock->getInsts()) | 
|  | { | 
|  | if(instruction.isDeleted()) | 
|  | { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | setNode(&instruction, basicBlock); | 
|  | if(instruction.getDest()) | 
|  | { | 
|  | setDefinition(instruction.getDest(), &instruction); | 
|  | } | 
|  |  | 
|  | for(Ice::SizeT i = 0; i < instruction.getSrcSize(); i++) | 
|  | { | 
|  | Ice::SizeT unique = 0; | 
|  | for(; unique < i; unique++) | 
|  | { | 
|  | if(instruction.getSrc(i) == instruction.getSrc(unique)) | 
|  | { | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(i == unique) | 
|  | { | 
|  | Ice::Operand *src = instruction.getSrc(i); | 
|  | getUses(src)->insert(src, &instruction); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void Optimizer::replace(Ice::Inst *instruction, Ice::Operand *newValue) | 
|  | { | 
|  | Ice::Variable *oldValue = instruction->getDest(); | 
|  |  | 
|  | if(!newValue) | 
|  | { | 
|  | newValue = context->getConstantUndef(oldValue->getType()); | 
|  | } | 
|  |  | 
|  | if(hasUses(oldValue)) | 
|  | { | 
|  | for(Ice::Inst *use : *getUses(oldValue)) | 
|  | { | 
|  | assert(!use->isDeleted());   // Should have been removed from uses already | 
|  |  | 
|  | for(Ice::SizeT i = 0; i < use->getSrcSize(); i++) | 
|  | { | 
|  | if(use->getSrc(i) == oldValue) | 
|  | { | 
|  | use->replaceSource(i, newValue); | 
|  | } | 
|  | } | 
|  |  | 
|  | getUses(newValue)->insert(newValue, use); | 
|  | } | 
|  |  | 
|  | setUses(oldValue, nullptr); | 
|  | } | 
|  |  | 
|  | deleteInstruction(instruction); | 
|  | } | 
|  |  | 
|  | void Optimizer::deleteInstruction(Ice::Inst *instruction) | 
|  | { | 
|  | if(!instruction || instruction->isDeleted()) | 
|  | { | 
|  | return; | 
|  | } | 
|  |  | 
|  | instruction->setDeleted(); | 
|  |  | 
|  | for(Ice::SizeT i = 0; i < instruction->getSrcSize(); i++) | 
|  | { | 
|  | Ice::Operand *src = instruction->getSrc(i); | 
|  |  | 
|  | if(hasUses(src)) | 
|  | { | 
|  | auto &srcUses = *getUses(src); | 
|  |  | 
|  | srcUses.erase(instruction); | 
|  |  | 
|  | if(srcUses.empty()) | 
|  | { | 
|  | setUses(src, nullptr); | 
|  |  | 
|  | if(Ice::Variable *var = llvm::dyn_cast<Ice::Variable>(src)) | 
|  | { | 
|  | deleteInstruction(getDefinition(var)); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bool Optimizer::isDead(Ice::Inst *instruction) | 
|  | { | 
|  | Ice::Variable *dest = instruction->getDest(); | 
|  |  | 
|  | if(dest) | 
|  | { | 
|  | return (!hasUses(dest) || getUses(dest)->empty()) && !instruction->hasSideEffects(); | 
|  | } | 
|  | else if(isStore(*instruction)) | 
|  | { | 
|  | if(Ice::Variable *address = llvm::dyn_cast<Ice::Variable>(storeAddress(instruction))) | 
|  | { | 
|  | Ice::Inst *def = getDefinition(address); | 
|  |  | 
|  | if(def && llvm::isa<Ice::InstAlloca>(def)) | 
|  | { | 
|  | if(hasUses(address)) | 
|  | { | 
|  | Optimizer::Uses* uses = getUses(address); | 
|  | return uses->size() == uses->stores.size();   // Dead if all uses are stores | 
|  | } | 
|  | else | 
|  | { | 
|  | return true; // No uses | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const Ice::InstIntrinsicCall *Optimizer::asLoadSubVector(const Ice::Inst *instruction) | 
|  | { | 
|  | if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction)) | 
|  | { | 
|  | if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::LoadSubVector) | 
|  | { | 
|  | return instrinsic; | 
|  | } | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | const Ice::InstIntrinsicCall *Optimizer::asStoreSubVector(const Ice::Inst *instruction) | 
|  | { | 
|  | if(auto *instrinsic = llvm::dyn_cast<Ice::InstIntrinsicCall>(instruction)) | 
|  | { | 
|  | if(instrinsic->getIntrinsicInfo().ID == Ice::Intrinsics::StoreSubVector) | 
|  | { | 
|  | return instrinsic; | 
|  | } | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | bool Optimizer::isLoad(const Ice::Inst &instruction) | 
|  | { | 
|  | if(llvm::isa<Ice::InstLoad>(&instruction)) | 
|  | { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return asLoadSubVector(&instruction) != nullptr; | 
|  | } | 
|  |  | 
|  | bool Optimizer::isStore(const Ice::Inst &instruction) | 
|  | { | 
|  | if(llvm::isa<Ice::InstStore>(&instruction)) | 
|  | { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return asStoreSubVector(&instruction) != nullptr; | 
|  | } | 
|  |  | 
|  | 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 *storeSubVector = asStoreSubVector(instruction)) | 
|  | { | 
|  | return storeSubVector->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 *loadSubVector = asLoadSubVector(instruction)) | 
|  | { | 
|  | return loadSubVector->getSrc(1); | 
|  | } | 
|  |  | 
|  | 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 *storeSubVector = asStoreSubVector(instruction)) | 
|  | { | 
|  | return storeSubVector->getSrc(1); | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | std::size_t Optimizer::storeSize(const Ice::Inst *store) | 
|  | { | 
|  | assert(isStore(*store)); | 
|  |  | 
|  | if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store)) | 
|  | { | 
|  | return Ice::typeWidthInBytes(instStore->getData()->getType()); | 
|  | } | 
|  |  | 
|  | if(auto *storeSubVector = asStoreSubVector(store)) | 
|  | { | 
|  | return llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue(); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | bool Optimizer::loadTypeMatchesStore(const Ice::Inst *load, const Ice::Inst *store) | 
|  | { | 
|  | if(!load || !store) | 
|  | { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | assert(isLoad(*load) && isStore(*store)); | 
|  | assert(loadAddress(load) == storeAddress(store)); | 
|  |  | 
|  | if(auto *instStore = llvm::dyn_cast<Ice::InstStore>(store)) | 
|  | { | 
|  | if(auto *instLoad = llvm::dyn_cast<Ice::InstLoad>(load)) | 
|  | { | 
|  | return instStore->getData()->getType() == instLoad->getDest()->getType(); | 
|  | } | 
|  | } | 
|  |  | 
|  | if(auto *storeSubVector = asStoreSubVector(store)) | 
|  | { | 
|  | if(auto *loadSubVector = asLoadSubVector(load)) | 
|  | { | 
|  | // Check for matching type and sub-vector width. | 
|  | return storeSubVector->getSrc(1)->getType() == loadSubVector->getDest()->getType() && | 
|  | llvm::cast<Ice::ConstantInteger32>(storeSubVector->getSrc(3))->getValue() == | 
|  | llvm::cast<Ice::ConstantInteger32>(loadSubVector->getSrc(2))->getValue(); | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Optimizer::Uses* Optimizer::getUses(Ice::Operand* operand) | 
|  | { | 
|  | Optimizer::Uses* uses = (Optimizer::Uses*)operand->Ice::Operand::getExternalData(); | 
|  | if(!uses) | 
|  | { | 
|  | uses = new Optimizer::Uses; | 
|  | setUses(operand, uses); | 
|  | allocatedUses.push_back(uses); | 
|  | } | 
|  | return uses; | 
|  | } | 
|  |  | 
|  | void Optimizer::setUses(Ice::Operand* operand, Optimizer::Uses* uses) | 
|  | { | 
|  | operand->Ice::Operand::setExternalData(uses); | 
|  | } | 
|  |  | 
|  | bool Optimizer::hasUses(Ice::Operand* operand) const | 
|  | { | 
|  | return operand->Ice::Operand::getExternalData() != nullptr; | 
|  | } | 
|  |  | 
|  | Ice::CfgNode* Optimizer::getNode(Ice::Inst* inst) | 
|  | { | 
|  | return (Ice::CfgNode*)inst->Ice::Inst::getExternalData(); | 
|  | } | 
|  |  | 
|  | void Optimizer::setNode(Ice::Inst* inst, Ice::CfgNode* node) | 
|  | { | 
|  | inst->Ice::Inst::setExternalData(node); | 
|  | } | 
|  |  | 
|  | Ice::Inst* Optimizer::getDefinition(Ice::Variable* var) | 
|  | { | 
|  | return (Ice::Inst*)var->Ice::Variable::getExternalData(); | 
|  | } | 
|  |  | 
|  | void Optimizer::setDefinition(Ice::Variable* var, Ice::Inst* inst) | 
|  | { | 
|  | var->Ice::Variable::setExternalData(inst); | 
|  | } | 
|  |  | 
|  | const std::vector<Optimizer::LoadStoreInst>& Optimizer::getLoadStoreInsts(Ice::CfgNode* node) | 
|  | { | 
|  | return *((const std::vector<LoadStoreInst>*)node->Ice::CfgNode::getExternalData()); | 
|  | } | 
|  |  | 
|  | void Optimizer::setLoadStoreInsts(Ice::CfgNode* node, std::vector<LoadStoreInst>* insts) | 
|  | { | 
|  | node->Ice::CfgNode::setExternalData(insts); | 
|  | } | 
|  |  | 
|  | bool Optimizer::hasLoadStoreInsts(Ice::CfgNode* node) const | 
|  | { | 
|  | return node->Ice::CfgNode::getExternalData() != 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(size_t i = 0; i < uses.size(); i++) | 
|  | { | 
|  | if(uses[i] == instruction) | 
|  | { | 
|  | uses[i] = back(); | 
|  | pop_back(); | 
|  |  | 
|  | for(size_t i = 0; i < loads.size(); i++) | 
|  | { | 
|  | if(loads[i] == instruction) | 
|  | { | 
|  | loads[i] = loads.back(); | 
|  | loads.pop_back(); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | for(size_t i = 0; i < stores.size(); i++) | 
|  | { | 
|  | if(stores[i] == instruction) | 
|  | { | 
|  | stores[i] = stores.back(); | 
|  | stores.pop_back(); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace rr | 
|  | { | 
|  | void optimize(Ice::Cfg *function) | 
|  | { | 
|  | Optimizer optimizer; | 
|  |  | 
|  | optimizer.run(function); | 
|  | } | 
|  | } |