Chromium Code Reviews| Index: src/IceCfg.cpp |
| diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp |
| index f71737994aba701b4a75e6dcd296b11a5f66fed9..4c45faa1ac6764ce9d0a4c3a90a494ff5f3d57d5 100644 |
| --- a/src/IceCfg.cpp |
| +++ b/src/IceCfg.cpp |
| @@ -507,6 +507,122 @@ void Cfg::shuffleNodes() { |
| dump("After basic block shuffling"); |
| } |
| +void Cfg::localCSE() { |
|
Jim Stichnoth
2016/05/23 16:52:56
I'd like to have a comment here briefly describing
manasijm
2016/05/23 23:13:30
Done.
|
| + TimerMarker T(TimerStack::TT_localCse, this); |
| + struct InstHash { |
| + size_t operator()(const Inst *Instr) const { |
| + auto Kind = Instr->getKind(); |
| + auto Result = |
| + std::hash<typename std::underlying_type<Inst::InstKind>::type>()( |
| + Kind); |
| + for (SizeT i = 0; i < Instr->getSrcSize(); ++i) { |
| + auto *Opnd = Instr->getSrc(i); |
| + if (auto *Var = llvm::dyn_cast<Variable>(Opnd)) { |
| + Result ^= std::hash<SizeT>()(Var->getIndex()); |
|
Jim Stichnoth
2016/05/23 16:52:57
This is a repetition of the VariableHash implement
manasijm
2016/05/23 23:13:30
Done.
|
| + } else if (Constant *Const = llvm::dyn_cast<Constant>(Opnd)) { |
| + Result ^= std::hash<Constant *>()(Const); |
| + // TODO : get Value of ConstantPrimitive |
|
Jim Stichnoth
2016/05/23 16:52:57
If I understand this correctly, your hash function
manasijm
2016/05/23 23:13:30
Done.
|
| + } else |
| + Result ^= std::hash<Operand *>()(Opnd); |
| + } |
| + return Result; |
| + } |
| + }; |
| + struct InstEq { |
| + bool srcEq(const Operand *A, const Operand *B) const { |
| + if (!(llvm::isa<Variable>(A) || (llvm::isa<Constant>(A))) || |
|
Jim Stichnoth
2016/05/23 16:52:56
This is really hard to read/understand. How about
manasijm
2016/05/23 23:13:30
Done.
|
| + !(llvm::isa<Variable>(B) || (llvm::isa<Constant>(B)))) |
| + return false; |
| + // No reason this has to an error. Returning false just disables the cse |
|
Jim Stichnoth
2016/05/23 16:52:57
"has to an error" ==> "has to be an error" ?
And
|
| + // optimization for this particular case |
| + return (A == B); |
| + } |
| + bool operator()(const Inst *InstrA, const Inst *InstrB) const { |
| + if ((InstrA->getKind() != InstrB->getKind()) || |
| + (InstrA->getSrcSize() != InstrB->getSrcSize())) |
| + return false; |
| + |
| + if (auto *A = llvm::dyn_cast<InstArithmetic>(InstrA)) { |
| + auto B = llvm::cast<InstArithmetic>(InstrB); |
|
Jim Stichnoth
2016/05/23 16:52:56
auto *
manasijm
2016/05/23 23:13:30
Done.
|
| + // A, B are guranteed to be of the same 'kind' at this point |
|
Jim Stichnoth
2016/05/23 16:52:57
guaranteed
manasijm
2016/05/23 23:13:30
Done.
|
| + // So, dyn_Cast is not needed |
|
Jim Stichnoth
2016/05/23 16:52:57
dyn_cast
manasijm
2016/05/23 23:13:30
Done.
|
| + if (A->getOp() != B->getOp()) |
| + return false; |
| + } |
| + // Does not enter loop if different kind or number of operands |
| + for (SizeT i = 0; i < InstrA->getSrcSize(); ++i) { |
| + if (!srcEq(InstrA->getSrc(i), InstrB->getSrc(i))) |
| + return false; |
| + } |
| + return true; |
| + } |
| + }; |
| + struct VariableHash { |
| + size_t operator()(const Variable *Var) const { |
| + return std::hash<SizeT>()(Var->getIndex()); |
| + } |
| + }; |
| + for (CfgNode *Node : getNodes()) { |
| + CfgUnorderedSet<Inst *, InstHash, InstEq> Seen; |
| + |
| + CfgUnorderedMap<Variable *, Variable *, VariableHash> Replacements; |
| + // Combining the above two into a single data structure might consume less |
| + // memory but will be slower i.e map of Instruction -> Set of Variables |
| + |
| + CfgUnorderedMap<Variable *, std::vector<Inst *>, VariableHash> Dependency; |
| + // Not necessary for SSA, still keeping it in case this pass is not run at |
| + // the beginning. Remove to improve performace. |
| + |
| + for (Inst &Instr : Node->getInsts()) { |
| + if (Instr.isDeleted() || !llvm::isa<InstArithmetic>(&Instr)) |
| + continue; |
| + |
| + // Invalidate replacements |
| + auto Iter = Replacements.find(Instr.getDest()); |
| + if (Iter != Replacements.end()) { |
| + Replacements.erase(Iter); |
| + } |
| + |
| + // Invalidate 'seen' instructions whose operands were just updated. |
| + auto DepIter = Dependency.find(Instr.getDest()); |
| + if (DepIter != Dependency.end()) { |
| + for (auto Dep : DepIter->second) { |
|
Jim Stichnoth
2016/05/23 16:52:57
I think this use of "auto" is getting too deep for
manasijm
2016/05/23 23:13:30
Done.
|
| + Seen.erase(Dep); |
| + } |
| + } |
| + // The above two can be removed if SSA is assumed. |
| + |
| + // Replace - doing this before checking for repetitions might enable more |
| + // optimizations |
| + for (SizeT i = 0; i < Instr.getSrcSize(); ++i) { |
| + auto *Opnd = Instr.getSrc(i); |
| + if (Variable *const Var = llvm::dyn_cast<Variable>(Opnd)) { |
|
Jim Stichnoth
2016/05/23 16:52:57
"Variable *const Var" just means that the value of
manasijm
2016/05/23 23:13:30
Artifact from first patch set.
|
| + if (Replacements.find(Var) != Replacements.end()) { |
| + Instr.replaceSource(i, Replacements[Var]); |
| + } |
| + } |
| + } |
| + |
| + // Check for repetitions |
| + auto SeenIter = Seen.find(&Instr); |
| + if (SeenIter != Seen.end()) { // seen before |
| + const Inst *Found = *SeenIter; |
| + Replacements[Instr.getDest()] = Found->getDest(); |
| + } else { // new |
| + Seen.insert(&Instr); |
| + |
| + // Update dependencies |
| + for (SizeT i = 0; i < Instr.getSrcSize(); ++i) { |
| + auto *Opnd = Instr.getSrc(i); |
| + if (auto *Var = llvm::dyn_cast<Variable>(Opnd)) { |
| + Dependency[Var].push_back(&Instr); |
| + } |
| + } |
| + } |
| + } |
| + } |
| +} |
| + |
| void Cfg::doArgLowering() { |
| TimerMarker T(TimerStack::TT_doArgLowering, this); |
| getTarget()->lowerArguments(); |