| Index: src/IceTargetLoweringX86BaseImpl.h
|
| diff --git a/src/IceTargetLoweringX86BaseImpl.h b/src/IceTargetLoweringX86BaseImpl.h
|
| index 4927e170598d69eded4aa851733b30ae89b114c8..d106280f542315c242fa0d3c9be0dd98709dfaf6 100644
|
| --- a/src/IceTargetLoweringX86BaseImpl.h
|
| +++ b/src/IceTargetLoweringX86BaseImpl.h
|
| @@ -151,6 +151,7 @@ private:
|
| return Element != Producers.end() && Element->second.Instr != nullptr;
|
| }
|
| void setInvalid(SizeT VarNum) { Producers[VarNum].Instr = nullptr; }
|
| + void invalidateProducersOnStore(const Inst *Instr);
|
| /// Producers maps Variable::Number to a BoolFoldingEntry.
|
| CfgUnorderedMap<SizeT, BoolFoldingEntry<Traits>> Producers;
|
| };
|
| @@ -252,10 +253,12 @@ bool BoolFolding<Traits>::isValidFolding(
|
| template <typename Traits> void BoolFolding<Traits>::init(CfgNode *Node) {
|
| Producers.clear();
|
| for (Inst &Instr : Node->getInsts()) {
|
| + if (Instr.isDeleted())
|
| + continue;
|
| + invalidateProducersOnStore(&Instr);
|
| // Check whether Instr is a valid producer.
|
| Variable *Var = Instr.getDest();
|
| - if (!Instr.isDeleted() // only consider non-deleted instructions
|
| - && Var // only instructions with an actual dest var
|
| + if (Var // only consider instructions with an actual dest var
|
| && Var->getType() == IceType_i1 // only bool-type dest vars
|
| && getProducerKind(&Instr) != PK_None) { // white-listed instructions
|
| Producers[Var->getIndex()] = BoolFoldingEntry<Traits>(&Instr);
|
| @@ -338,6 +341,43 @@ void BoolFolding<Traits>::dump(const Cfg *Func) const {
|
| }
|
| }
|
|
|
| +/// If the given instruction has potential memory side effects (e.g. store, rmw,
|
| +/// or a call instruction with potential memory side effects), then we must not
|
| +/// allow a pre-store Producer instruction with memory operands to be folded
|
| +/// into a post-store Consumer instruction. If this is detected, the Producer
|
| +/// is invalidated.
|
| +///
|
| +/// We use the Producer's IsLiveOut field to determine whether any potential
|
| +/// Consumers come after this store instruction. The IsLiveOut field is
|
| +/// initialized to true, and BoolFolding::init() sets IsLiveOut to false when it
|
| +/// sees the variable's definitive last use (indicating the variable is not in
|
| +/// the node's live-out set). Thus if we see here that IsLiveOut is false, we
|
| +/// know that there can be no consumers after the store, and therefore we know
|
| +/// the folding is safe despite the store instruction.
|
| +template <typename Traits>
|
| +void BoolFolding<Traits>::invalidateProducersOnStore(const Inst *Instr) {
|
| + if (!Instr->isMemoryWrite())
|
| + return;
|
| + for (auto &ProducerPair : Producers) {
|
| + if (!ProducerPair.second.IsLiveOut)
|
| + continue;
|
| + Inst *PInst = ProducerPair.second.Instr;
|
| + if (PInst == nullptr)
|
| + continue;
|
| + bool HasMemOperand = false;
|
| + const SizeT SrcSize = PInst->getSrcSize();
|
| + for (SizeT I = 0; I < SrcSize; ++I) {
|
| + if (llvm::isa<typename Traits::X86OperandMem>(PInst->getSrc(I))) {
|
| + HasMemOperand = true;
|
| + break;
|
| + }
|
| + }
|
| + if (!HasMemOperand)
|
| + continue;
|
| + setInvalid(ProducerPair.first);
|
| + }
|
| +}
|
| +
|
| template <typename TraitsType>
|
| void TargetX86Base<TraitsType>::initNodeForLowering(CfgNode *Node) {
|
| FoldingInfo.init(Node);
|
|
|