diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h index ba7fc62e40042..0d88f55451d43 100644 --- a/llvm/include/llvm/CodeGen/SelectionDAG.h +++ b/llvm/include/llvm/CodeGen/SelectionDAG.h @@ -275,6 +275,7 @@ class SelectionDAG { struct NodeExtraInfo { CallSiteInfo CSInfo; MDNode *HeapAllocSite = nullptr; + MDNode *PCSections = nullptr; bool NoMerge = false; }; /// Out-of-line extra information for SDNodes. @@ -336,6 +337,19 @@ class SelectionDAG { virtual void anchor(); }; + struct DAGNodeInsertedListener : public DAGUpdateListener { + std::function Callback; + + DAGNodeInsertedListener(SelectionDAG &DAG, + std::function Callback) + : DAGUpdateListener(DAG), Callback(std::move(Callback)) {} + + void NodeInserted(SDNode *N) override { Callback(N); } + + private: + virtual void anchor(); + }; + /// Help to insert SDNodeFlags automatically in transforming. Use /// RAII to save and resume flags in current scope. class FlagInserter { @@ -2184,6 +2198,15 @@ class SelectionDAG { auto I = SDEI.find(Node); return I != SDEI.end() ? I->second.HeapAllocSite : nullptr; } + /// Set PCSections to be associated with Node. + void addPCSections(const SDNode *Node, MDNode *MD) { + SDEI[Node].PCSections = MD; + } + /// Return PCSections associated with Node, or nullptr if none exists. + MDNode *getPCSections(const SDNode *Node) const { + auto It = SDEI.find(Node); + return It != SDEI.end() ? It->second.PCSections : nullptr; + } /// Set NoMergeSiteInfo to be associated with Node if NoMerge is true. void addNoMergeSiteInfo(const SDNode *Node, bool NoMerge) { if (NoMerge) diff --git a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp index 5166db033c629..bb0f29bbaad4f 100644 --- a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp @@ -890,6 +890,9 @@ EmitSchedule(MachineBasicBlock::iterator &InsertPos) { MI->setFlag(MachineInstr::MIFlag::NoMerge); } + if (MDNode *MD = DAG->getPCSections(Node)) + MI->setPCSections(MF, MD); + return MI; }; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 97b14b46e720e..70e046571c590 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -92,6 +92,7 @@ void SelectionDAG::DAGUpdateListener::NodeUpdated(SDNode*) {} void SelectionDAG::DAGUpdateListener::NodeInserted(SDNode *) {} void SelectionDAG::DAGNodeDeletedListener::anchor() {} +void SelectionDAG::DAGNodeInsertedListener::anchor() {} #define DEBUG_TYPE "selectiondag" diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 4c21dfc4392a5..bc72e45cb4411 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1123,12 +1123,36 @@ void SelectionDAGBuilder::visit(const Instruction &I) { CurInst = &I; + // Set inserted listener only if required. + bool NodeInserted = false; + std::unique_ptr InsertedListener; + MDNode *PCSectionsMD = I.getMetadata(LLVMContext::MD_pcsections); + if (PCSectionsMD) { + InsertedListener = std::make_unique( + DAG, [&](SDNode *) { NodeInserted = true; }); + } + visit(I.getOpcode(), I); if (!I.isTerminator() && !HasTailCall && !isa(I)) // statepoints handle their exports internally CopyToExportRegsIfNeeded(&I); + // Handle metadata. + if (PCSectionsMD) { + auto It = NodeMap.find(&I); + if (It != NodeMap.end()) { + DAG.addPCSections(It->second.getNode(), PCSectionsMD); + } else if (NodeInserted) { + // This should not happen; if it does, don't let it go unnoticed so we can + // fix it. Relevant visit*() function is probably missing a setValue(). + errs() << "warning: loosing !pcsections metadata [" + << I.getModule()->getName() << "]\n"; + LLVM_DEBUG(I.dump()); + assert(false); + } + } + CurInst = nullptr; } @@ -2543,6 +2567,8 @@ void SelectionDAGBuilder::visitSwitchCase(CaseBlock &CB, MVT::Other, getControlRoot(), Cond, DAG.getBasicBlock(CB.TrueBB)); + setValue(CurInst, BrCond); + // Insert the false branch. Do this even if it's a fall through branch, // this makes it easier to do DAG optimizations which require inverting // the branch condition. @@ -4303,6 +4329,7 @@ void SelectionDAGBuilder::visitStore(const StoreInst &I) { SDValue StoreNode = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, makeArrayRef(Chains.data(), ChainI)); + setValue(&I, StoreNode); DAG.setRoot(StoreNode); } @@ -4667,7 +4694,9 @@ void SelectionDAGBuilder::visitFence(const FenceInst &I) { TLI.getFenceOperandTy(DAG.getDataLayout())); Ops[2] = DAG.getTargetConstant(I.getSyncScopeID(), dl, TLI.getFenceOperandTy(DAG.getDataLayout())); - DAG.setRoot(DAG.getNode(ISD::ATOMIC_FENCE, dl, MVT::Other, Ops)); + SDValue N = DAG.getNode(ISD::ATOMIC_FENCE, dl, MVT::Other, Ops); + setValue(&I, N); + DAG.setRoot(N); } void SelectionDAGBuilder::visitAtomicLoad(const LoadInst &I) { @@ -4754,13 +4783,14 @@ void SelectionDAGBuilder::visitAtomicStore(const StoreInst &I) { // TODO: Once this is better exercised by tests, it should be merged with // the normal path for stores to prevent future divergence. SDValue S = DAG.getStore(InChain, dl, Val, Ptr, MMO); + setValue(&I, S); DAG.setRoot(S); return; } SDValue OutChain = DAG.getAtomic(ISD::ATOMIC_STORE, dl, MemVT, InChain, Ptr, Val, MMO); - + setValue(&I, OutChain); DAG.setRoot(OutChain); } diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index d46a0a23cca3e..366eb7ab42510 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -997,6 +997,15 @@ class ISelUpdater : public SelectionDAG::DAGUpdateListener { if (ISelPosition == SelectionDAG::allnodes_iterator(N)) ++ISelPosition; } + + /// NodeInserted - Handle new nodes inserted into the graph: propagate + /// metadata from root nodes that also applies to new nodes, in case the root + /// is later deleted. + void NodeInserted(SDNode *N) override { + SDNode *CurNode = &*ISelPosition; + if (MDNode *MD = DAG.getPCSections(CurNode)) + DAG.addPCSections(N, MD); + } }; } // end anonymous namespace @@ -1073,7 +1082,7 @@ void SelectionDAGISel::DoInstructionSelection() { ++ISelPosition; // Make sure that ISelPosition gets properly updated when nodes are deleted - // in calls made from this function. + // in calls made from this function. New nodes inherit relevant metadata. ISelUpdater ISU(*CurDAG, ISelPosition); // The AllNodes list is now topological-sorted. Visit the diff --git a/llvm/unittests/CodeGen/AArch64SelectionDAGTest.cpp b/llvm/unittests/CodeGen/AArch64SelectionDAGTest.cpp index 1fedcf1467440..94171001691fc 100644 --- a/llvm/unittests/CodeGen/AArch64SelectionDAGTest.cpp +++ b/llvm/unittests/CodeGen/AArch64SelectionDAGTest.cpp @@ -601,11 +601,14 @@ TEST_F(AArch64SelectionDAGTest, ReplaceAllUsesWith) { SDValue N2 = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N1); EXPECT_FALSE(DAG->getHeapAllocSite(N2.getNode())); EXPECT_FALSE(DAG->getNoMergeSiteInfo(N2.getNode())); + EXPECT_FALSE(DAG->getPCSections(N2.getNode())); MDNode *MD = MDNode::get(Context, None); DAG->addHeapAllocSite(N2.getNode(), MD); DAG->addNoMergeSiteInfo(N2.getNode(), true); + DAG->addPCSections(N2.getNode(), MD); EXPECT_EQ(DAG->getHeapAllocSite(N2.getNode()), MD); EXPECT_TRUE(DAG->getNoMergeSiteInfo(N2.getNode())); + EXPECT_EQ(DAG->getPCSections(N2.getNode()), MD); SDValue Root = DAG->getNode(ISD::ADD, Loc, IntVT, N2, N2); EXPECT_EQ(Root->getOperand(0)->getOpcode(), ISD::SUB); @@ -613,11 +616,13 @@ TEST_F(AArch64SelectionDAGTest, ReplaceAllUsesWith) { SDValue New = DAG->getNode(ISD::ADD, Loc, IntVT, N1, N1); EXPECT_FALSE(DAG->getHeapAllocSite(New.getNode())); EXPECT_FALSE(DAG->getNoMergeSiteInfo(New.getNode())); + EXPECT_FALSE(DAG->getPCSections(New.getNode())); DAG->ReplaceAllUsesWith(N2, New); EXPECT_EQ(Root->getOperand(0), New); EXPECT_EQ(DAG->getHeapAllocSite(New.getNode()), MD); EXPECT_TRUE(DAG->getNoMergeSiteInfo(New.getNode())); + EXPECT_EQ(DAG->getPCSections(New.getNode()), MD); } } // end namespace llvm