[llvm] r271345 - CodeGen: Refactor renameDisconnectedComponents() as a pass
Matthias Braun via llvm-commits
llvm-commits at lists.llvm.org
Tue May 31 15:38:07 PDT 2016
Author: matze
Date: Tue May 31 17:38:06 2016
New Revision: 271345
URL: http://llvm.org/viewvc/llvm-project?rev=271345&view=rev
Log:
CodeGen: Refactor renameDisconnectedComponents() as a pass
Refactor LiveIntervals::renameDisconnectedComponents() to be a pass.
Also change the name to "RenameIndependentSubregs":
- renameDisconnectedComponents() worked on a MachineFunction at a time
so it is a natural candidate for a machine function pass.
- The algorithm is testable with a .mir test now.
- This also fixes a problem where the lazy renaming as part of the
MachineScheduler introduced IMPLICIT_DEF instructions after the number
of a nodes in a region were counted leading to a mismatch.
Differential Revision: http://reviews.llvm.org/D20507
Added:
llvm/trunk/lib/CodeGen/LiveRangeUtils.h
llvm/trunk/lib/CodeGen/RenameIndependentSubregs.cpp
llvm/trunk/test/CodeGen/AMDGPU/rename-independent-subregs.mir
Modified:
llvm/trunk/include/llvm/CodeGen/LiveInterval.h
llvm/trunk/include/llvm/CodeGen/LiveIntervalAnalysis.h
llvm/trunk/include/llvm/CodeGen/Passes.h
llvm/trunk/include/llvm/InitializePasses.h
llvm/trunk/lib/CodeGen/CMakeLists.txt
llvm/trunk/lib/CodeGen/CodeGen.cpp
llvm/trunk/lib/CodeGen/LiveInterval.cpp
llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp
llvm/trunk/lib/CodeGen/MachineScheduler.cpp
llvm/trunk/lib/CodeGen/TargetPassConfig.cpp
Modified: llvm/trunk/include/llvm/CodeGen/LiveInterval.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/LiveInterval.h?rev=271345&r1=271344&r2=271345&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/LiveInterval.h (original)
+++ llvm/trunk/include/llvm/CodeGen/LiveInterval.h Tue May 31 17:38:06 2016
@@ -864,77 +864,5 @@ namespace llvm {
void Distribute(LiveInterval &LI, LiveInterval *LIV[],
MachineRegisterInfo &MRI);
};
-
- /// Helper class that can divide MachineOperands of a virtual register into
- /// equivalence classes of connected components.
- /// MachineOperands belong to the same equivalence class when they are part of
- /// the same SubRange segment or adjacent segments (adjacent in control
- /// flow); Different subranges affected by the same MachineOperand belong to
- /// the same equivalence class.
- ///
- /// Example:
- /// vreg0:sub0 = ...
- /// vreg0:sub1 = ...
- /// vreg0:sub2 = ...
- /// ...
- /// xxx = op vreg0:sub1
- /// vreg0:sub1 = ...
- /// store vreg0:sub0_sub1
- ///
- /// The example contains 3 different equivalence classes:
- /// - One for the (dead) vreg0:sub2 definition
- /// - One containing the first vreg0:sub1 definition and its use,
- /// but not the second definition!
- /// - The remaining class contains all other operands involving vreg0.
- ///
- /// We provide a utility function here to rename disjunct classes to different
- /// virtual registers.
- class ConnectedSubRegClasses {
- LiveIntervals &LIS;
- MachineRegisterInfo &MRI;
- const TargetInstrInfo &TII;
-
- public:
- ConnectedSubRegClasses(LiveIntervals &LIS, MachineRegisterInfo &MRI,
- const TargetInstrInfo &TII)
- : LIS(LIS), MRI(MRI), TII(TII) {}
-
- /// Split unrelated subregister components and rename them to new vregs.
- void renameComponents(LiveInterval &LI) const;
-
- private:
- struct SubRangeInfo {
- ConnectedVNInfoEqClasses ConEQ;
- LiveInterval::SubRange *SR;
- unsigned Index;
-
- SubRangeInfo(LiveIntervals &LIS, LiveInterval::SubRange &SR,
- unsigned Index)
- : ConEQ(LIS), SR(&SR), Index(Index) {}
- };
-
- /// \brief Build a vector of SubRange infos and a union find set of
- /// equivalence classes.
- /// Returns true if more than 1 equivalence class was found.
- bool findComponents(IntEqClasses &Classes,
- SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
- LiveInterval &LI) const;
-
- /// \brief Distribute the LiveInterval segments into the new LiveIntervals
- /// belonging to their class.
- void distribute(const IntEqClasses &Classes,
- const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
- const SmallVectorImpl<LiveInterval*> &Intervals) const;
-
- /// \brief Constructs main liverange and add missing undef+dead flags.
- void computeMainRangesFixFlags(const IntEqClasses &Classes,
- const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
- const SmallVectorImpl<LiveInterval*> &Intervals) const;
-
- /// Rewrite Machine Operands to use the new vreg belonging to their class.
- void rewriteOperands(const IntEqClasses &Classes,
- const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
- const SmallVectorImpl<LiveInterval*> &Intervals) const;
- };
}
#endif
Modified: llvm/trunk/include/llvm/CodeGen/LiveIntervalAnalysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/LiveIntervalAnalysis.h?rev=271345&r1=271344&r2=271345&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/LiveIntervalAnalysis.h (original)
+++ llvm/trunk/include/llvm/CodeGen/LiveIntervalAnalysis.h Tue May 31 17:38:06 2016
@@ -405,11 +405,6 @@ extern cl::opt<bool> UseSegmentSetForPhy
void splitSeparateComponents(LiveInterval &LI,
SmallVectorImpl<LiveInterval*> &SplitLIs);
- /// Assure dead subregister definitions have their own vreg assigned.
- /// This calls ConnectedSubRegClasses::splitSeparateSubRegComponent()
- /// on each virtual register.
- void renameDisconnectedComponents();
-
/// For live interval \p LI with correct SubRanges construct matching
/// information for the main live range. Expects the main live range to not
/// have any segments or value numbers.
Modified: llvm/trunk/include/llvm/CodeGen/Passes.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/Passes.h?rev=271345&r1=271344&r2=271345&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/Passes.h (original)
+++ llvm/trunk/include/llvm/CodeGen/Passes.h Tue May 31 17:38:06 2016
@@ -356,6 +356,11 @@ namespace llvm {
/// This pass splits the stack into a safe stack and an unsafe stack to
/// protect against stack-based overflow vulnerabilities.
FunctionPass *createSafeStackPass(const TargetMachine *TM = nullptr);
+
+ /// This pass detects subregister lanes in a virtual register that are used
+ /// independently of other lanes and splits them into separate virtual
+ /// registers.
+ extern char &RenameIndependentSubregsID;
} // End llvm namespace
/// Target machine pass initializer for passes with dependencies. Use with
Modified: llvm/trunk/include/llvm/InitializePasses.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=271345&r1=271344&r2=271345&view=diff
==============================================================================
--- llvm/trunk/include/llvm/InitializePasses.h (original)
+++ llvm/trunk/include/llvm/InitializePasses.h Tue May 31 17:38:06 2016
@@ -266,6 +266,7 @@ void initializeRegionOnlyPrinterPass(Pas
void initializeRegionOnlyViewerPass(PassRegistry&);
void initializeRegionPrinterPass(PassRegistry&);
void initializeRegionViewerPass(PassRegistry&);
+void initializeRenameIndependentSubregsPass(PassRegistry&);
void initializeReversePostOrderFunctionAttrsPass(PassRegistry&);
void initializeRewriteStatepointsForGCPass(PassRegistry&);
void initializeSafeStackPass(PassRegistry&);
Modified: llvm/trunk/lib/CodeGen/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CMakeLists.txt?rev=271345&r1=271344&r2=271345&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/CMakeLists.txt (original)
+++ llvm/trunk/lib/CodeGen/CMakeLists.txt Tue May 31 17:38:06 2016
@@ -100,6 +100,7 @@ add_llvm_library(LLVMCodeGen
RegisterCoalescer.cpp
RegisterPressure.cpp
RegisterScavenging.cpp
+ RenameIndependentSubregs.cpp
SafeStack.cpp
ScheduleDAG.cpp
ScheduleDAGInstrs.cpp
Modified: llvm/trunk/lib/CodeGen/CodeGen.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CodeGen.cpp?rev=271345&r1=271344&r2=271345&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/CodeGen.cpp (original)
+++ llvm/trunk/lib/CodeGen/CodeGen.cpp Tue May 31 17:38:06 2016
@@ -68,6 +68,7 @@ void llvm::initializeCodeGen(PassRegistr
initializePreISelIntrinsicLoweringPass(Registry);
initializeProcessImplicitDefsPass(Registry);
initializeRegisterCoalescerPass(Registry);
+ initializeRenameIndependentSubregsPass(Registry);
initializeShrinkWrapPass(Registry);
initializeSlotIndexesPass(Registry);
initializeStackColoringPass(Registry);
Modified: llvm/trunk/lib/CodeGen/LiveInterval.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LiveInterval.cpp?rev=271345&r1=271344&r2=271345&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/LiveInterval.cpp (original)
+++ llvm/trunk/lib/CodeGen/LiveInterval.cpp Tue May 31 17:38:06 2016
@@ -20,16 +20,14 @@
#include "llvm/CodeGen/LiveInterval.h"
-#include "PHIEliminationUtils.h"
+#include "LiveRangeUtils.h"
#include "RegisterCoalescer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include <algorithm>
using namespace llvm;
@@ -1176,40 +1174,6 @@ unsigned ConnectedVNInfoEqClasses::Class
return EqClass.getNumClasses();
}
-template<typename LiveRangeT, typename EqClassesT>
-static void DistributeRange(LiveRangeT &LR, LiveRangeT *SplitLRs[],
- EqClassesT VNIClasses) {
- // Move segments to new intervals.
- LiveRange::iterator J = LR.begin(), E = LR.end();
- while (J != E && VNIClasses[J->valno->id] == 0)
- ++J;
- for (LiveRange::iterator I = J; I != E; ++I) {
- if (unsigned eq = VNIClasses[I->valno->id]) {
- assert((SplitLRs[eq-1]->empty() || SplitLRs[eq-1]->expiredAt(I->start)) &&
- "New intervals should be empty");
- SplitLRs[eq-1]->segments.push_back(*I);
- } else
- *J++ = *I;
- }
- LR.segments.erase(J, E);
-
- // Transfer VNInfos to their new owners and renumber them.
- unsigned j = 0, e = LR.getNumValNums();
- while (j != e && VNIClasses[j] == 0)
- ++j;
- for (unsigned i = j; i != e; ++i) {
- VNInfo *VNI = LR.getValNumInfo(i);
- if (unsigned eq = VNIClasses[i]) {
- VNI->id = SplitLRs[eq-1]->getNumValNums();
- SplitLRs[eq-1]->valnos.push_back(VNI);
- } else {
- VNI->id = j;
- LR.valnos[j++] = VNI;
- }
- }
- LR.valnos.resize(j);
-}
-
void ConnectedVNInfoEqClasses::Distribute(LiveInterval &LI, LiveInterval *LIV[],
MachineRegisterInfo &MRI) {
// Rewrite instructions.
@@ -1276,232 +1240,3 @@ void ConnectedVNInfoEqClasses::Distribut
// Distribute main liverange.
DistributeRange(LI, LIV, EqClass);
}
-
-void ConnectedSubRegClasses::renameComponents(LiveInterval &LI) const {
- // Shortcut: We cannot have split components with a single definition.
- if (LI.valnos.size() < 2)
- return;
-
- SmallVector<SubRangeInfo, 4> SubRangeInfos;
- IntEqClasses Classes;
- if (!findComponents(Classes, SubRangeInfos, LI))
- return;
-
- // Create a new VReg for each class.
- unsigned Reg = LI.reg;
- const TargetRegisterClass *RegClass = MRI.getRegClass(Reg);
- SmallVector<LiveInterval*, 4> Intervals;
- Intervals.push_back(&LI);
- for (unsigned I = 1, NumClasses = Classes.getNumClasses(); I < NumClasses;
- ++I) {
- unsigned NewVReg = MRI.createVirtualRegister(RegClass);
- LiveInterval &NewLI = LIS.createEmptyInterval(NewVReg);
- Intervals.push_back(&NewLI);
- }
-
- rewriteOperands(Classes, SubRangeInfos, Intervals);
- distribute(Classes, SubRangeInfos, Intervals);
- computeMainRangesFixFlags(Classes, SubRangeInfos, Intervals);
-}
-
-bool ConnectedSubRegClasses::findComponents(IntEqClasses &Classes,
- SmallVectorImpl<ConnectedSubRegClasses::SubRangeInfo> &SubRangeInfos,
- LiveInterval &LI) const {
- // First step: Create connected components for the VNInfos inside the
- // subranges and count the global number of such components.
- unsigned NumComponents = 0;
- for (LiveInterval::SubRange &SR : LI.subranges()) {
- SubRangeInfos.push_back(SubRangeInfo(LIS, SR, NumComponents));
- ConnectedVNInfoEqClasses &ConEQ = SubRangeInfos.back().ConEQ;
-
- unsigned NumSubComponents = ConEQ.Classify(SR);
- NumComponents += NumSubComponents;
- }
- // Shortcut: With only 1 subrange, the normal separate component tests are
- // enough and we do not need to perform the union-find on the subregister
- // segments.
- if (SubRangeInfos.size() < 2)
- return false;
-
- // Next step: Build union-find structure over all subranges and merge classes
- // across subranges when they are affected by the same MachineOperand.
- const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();
- Classes.grow(NumComponents);
- unsigned Reg = LI.reg;
- for (const MachineOperand &MO : MRI.reg_nodbg_operands(Reg)) {
- if (!MO.isDef() && !MO.readsReg())
- continue;
- unsigned SubRegIdx = MO.getSubReg();
- LaneBitmask LaneMask = TRI.getSubRegIndexLaneMask(SubRegIdx);
- unsigned MergedID = ~0u;
- for (ConnectedSubRegClasses::SubRangeInfo &SRInfo : SubRangeInfos) {
- const LiveInterval::SubRange &SR = *SRInfo.SR;
- if ((SR.LaneMask & LaneMask) == 0)
- continue;
- SlotIndex Pos = LIS.getInstructionIndex(*MO.getParent());
- Pos = MO.isDef() ? Pos.getRegSlot(MO.isEarlyClobber())
- : Pos.getBaseIndex();
- const VNInfo *VNI = SR.getVNInfoAt(Pos);
- if (VNI == nullptr)
- continue;
-
- // Map to local representant ID.
- unsigned LocalID = SRInfo.ConEQ.getEqClass(VNI);
- // Global ID
- unsigned ID = LocalID + SRInfo.Index;
- // Merge other sets
- MergedID = MergedID == ~0u ? ID : Classes.join(MergedID, ID);
- }
- }
-
- // Early exit if we ended up with a single equivalence class.
- Classes.compress();
- unsigned NumClasses = Classes.getNumClasses();
- return NumClasses > 1;
-}
-
-void ConnectedSubRegClasses::rewriteOperands(const IntEqClasses &Classes,
- const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
- const SmallVectorImpl<LiveInterval*> &Intervals) const {
- const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();
- unsigned Reg = Intervals[0]->reg;;
- for (MachineRegisterInfo::reg_nodbg_iterator I = MRI.reg_nodbg_begin(Reg),
- E = MRI.reg_nodbg_end(); I != E; ) {
- MachineOperand &MO = *I++;
- if (!MO.isDef() && !MO.readsReg())
- continue;
-
- MachineInstr &MI = *MO.getParent();
-
- SlotIndex Pos = LIS.getInstructionIndex(MI);
- unsigned SubRegIdx = MO.getSubReg();
- LaneBitmask LaneMask = TRI.getSubRegIndexLaneMask(SubRegIdx);
-
- unsigned ID = ~0u;
- for (const SubRangeInfo &SRInfo : SubRangeInfos) {
- const LiveInterval::SubRange &SR = *SRInfo.SR;
- if ((SR.LaneMask & LaneMask) == 0)
- continue;
- LiveRange::const_iterator I = SR.find(Pos);
- if (I == SR.end())
- continue;
-
- const VNInfo &VNI = *I->valno;
- // Map to local representant ID.
- unsigned LocalID = SRInfo.ConEQ.getEqClass(&VNI);
- // Global ID
- ID = Classes[LocalID + SRInfo.Index];
- break;
- }
-
- unsigned VReg = Intervals[ID]->reg;
- MO.setReg(VReg);
- }
-}
-
-void ConnectedSubRegClasses::distribute(const IntEqClasses &Classes,
- const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
- const SmallVectorImpl<LiveInterval*> &Intervals) const {
- unsigned NumClasses = Classes.getNumClasses();
- SmallVector<unsigned, 8> VNIMapping;
- SmallVector<LiveInterval::SubRange*, 8> SubRanges;
- BumpPtrAllocator &Allocator = LIS.getVNInfoAllocator();
- for (const SubRangeInfo &SRInfo : SubRangeInfos) {
- LiveInterval::SubRange &SR = *SRInfo.SR;
- unsigned NumValNos = SR.valnos.size();
- VNIMapping.clear();
- VNIMapping.reserve(NumValNos);
- SubRanges.clear();
- SubRanges.resize(NumClasses-1, nullptr);
- for (unsigned I = 0; I < NumValNos; ++I) {
- const VNInfo &VNI = *SR.valnos[I];
- unsigned LocalID = SRInfo.ConEQ.getEqClass(&VNI);
- unsigned ID = Classes[LocalID + SRInfo.Index];
- VNIMapping.push_back(ID);
- if (ID > 0 && SubRanges[ID-1] == nullptr)
- SubRanges[ID-1] = Intervals[ID]->createSubRange(Allocator, SR.LaneMask);
- }
- DistributeRange(SR, SubRanges.data(), VNIMapping);
- }
-}
-
-static bool subRangeLiveAt(const LiveInterval &LI, SlotIndex Pos) {
- for (const LiveInterval::SubRange &SR : LI.subranges()) {
- if (SR.liveAt(Pos))
- return true;
- }
- return false;
-}
-
-void ConnectedSubRegClasses::computeMainRangesFixFlags(
- const IntEqClasses &Classes,
- const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
- const SmallVectorImpl<LiveInterval*> &Intervals) const {
- BumpPtrAllocator &Allocator = LIS.getVNInfoAllocator();
- const SlotIndexes &Indexes = *LIS.getSlotIndexes();
- for (size_t I = 0, E = Intervals.size(); I < E; ++I) {
- LiveInterval &LI = *Intervals[I];
- unsigned Reg = LI.reg;
-
- LI.removeEmptySubRanges();
-
- // There must be a def (or live-in) before every use. Splitting vregs may
- // violate this principle as the splitted vreg may not have a definition on
- // every path. Fix this by creating IMPLICIT_DEF instruction as necessary.
- for (const LiveInterval::SubRange &SR : LI.subranges()) {
- // Search for "PHI" value numbers in the subranges. We must find a live
- // value in each predecessor block, add an IMPLICIT_DEF where it is
- // missing.
- for (unsigned I = 0; I < SR.valnos.size(); ++I) {
- const VNInfo &VNI = *SR.valnos[I];
- if (VNI.isUnused() || !VNI.isPHIDef())
- continue;
-
- SlotIndex Def = VNI.def;
- MachineBasicBlock &MBB = *Indexes.getMBBFromIndex(Def);
- for (MachineBasicBlock *PredMBB : MBB.predecessors()) {
- SlotIndex PredEnd = Indexes.getMBBEndIdx(PredMBB);
- if (subRangeLiveAt(LI, PredEnd.getPrevSlot()))
- continue;
-
- MachineBasicBlock::iterator InsertPos =
- llvm::findPHICopyInsertPoint(PredMBB, &MBB, Reg);
- const MCInstrDesc &MCDesc = TII.get(TargetOpcode::IMPLICIT_DEF);
- MachineInstrBuilder ImpDef = BuildMI(*PredMBB, InsertPos,
- DebugLoc(), MCDesc, Reg);
- SlotIndex DefIdx = LIS.InsertMachineInstrInMaps(*ImpDef);
- SlotIndex RegDefIdx = DefIdx.getRegSlot();
- for (LiveInterval::SubRange &SR : LI.subranges()) {
- VNInfo *SRVNI = SR.getNextValue(RegDefIdx, Allocator);
- SR.addSegment(LiveRange::Segment(RegDefIdx, PredEnd, SRVNI));
- }
- }
- }
- }
-
- for (MachineOperand &MO : MRI.reg_nodbg_operands(Reg)) {
- if (!MO.isDef())
- continue;
- unsigned SubRegIdx = MO.getSubReg();
- if (SubRegIdx == 0)
- continue;
- // After assigning the new vreg we may not have any other sublanes living
- // in and out of the instruction anymore. We need to add new dead and
- // undef flags in these cases.
- if (!MO.isUndef()) {
- SlotIndex Pos = LIS.getInstructionIndex(*MO.getParent());
- if (!subRangeLiveAt(LI, Pos))
- MO.setIsUndef();
- }
- if (!MO.isDead()) {
- SlotIndex Pos = LIS.getInstructionIndex(*MO.getParent()).getDeadSlot();
- if (!subRangeLiveAt(LI, Pos))
- MO.setIsDead();
- }
- }
-
- if (I == 0)
- LI.clear();
- LIS.constructMainRangeFromSubranges(LI);
- }
-}
Modified: llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp?rev=271345&r1=271344&r2=271345&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp (original)
+++ llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp Tue May 31 17:38:06 2016
@@ -1566,22 +1566,6 @@ void LiveIntervals::splitSeparateCompone
ConEQ.Distribute(LI, SplitLIs.data(), *MRI);
}
-void LiveIntervals::renameDisconnectedComponents() {
- ConnectedSubRegClasses SubRegClasses(*this, *MRI, *TII);
-
- // Iterate over all vregs. Note that we query getNumVirtRegs() the newly
- // created vregs end up with higher numbers but do not need to be visited as
- // there can't be any further splitting.
- for (size_t I = 0, E = MRI->getNumVirtRegs(); I < E; ++I) {
- unsigned Reg = TargetRegisterInfo::index2VirtReg(I);
- LiveInterval *LI = VirtRegIntervals[Reg];
- if (LI == nullptr || !LI->hasSubRanges())
- continue;
-
- SubRegClasses.renameComponents(*LI);
- }
-}
-
void LiveIntervals::constructMainRangeFromSubranges(LiveInterval &LI) {
assert(LRCalc && "LRCalc not initialized.");
LRCalc->reset(MF, getSlotIndexes(), DomTree, &getVNInfoAllocator());
Added: llvm/trunk/lib/CodeGen/LiveRangeUtils.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LiveRangeUtils.h?rev=271345&view=auto
==============================================================================
--- llvm/trunk/lib/CodeGen/LiveRangeUtils.h (added)
+++ llvm/trunk/lib/CodeGen/LiveRangeUtils.h Tue May 31 17:38:06 2016
@@ -0,0 +1,62 @@
+//===-- LiveRangeUtils.h - Live Range modification utilities ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// This file contains helper functions to modify live ranges.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_CODEGEN_LIVERANGEUTILS_H
+#define LLVM_LIB_CODEGEN_LIVERANGEUTILS_H
+
+#include "llvm/CodeGen/LiveInterval.h"
+
+namespace llvm {
+
+/// Helper function that distributes live range value numbers and the
+/// corresponding segments of a master live range \p LR to a list of newly
+/// created live ranges \p SplitLRs. \p VNIClasses maps each value number in \p
+/// LR to 0 meaning it should stay or to 1..N meaning it should go to a specific
+/// live range in the \p SplitLRs array.
+template<typename LiveRangeT, typename EqClassesT>
+static void DistributeRange(LiveRangeT &LR, LiveRangeT *SplitLRs[],
+ EqClassesT VNIClasses) {
+ // Move segments to new intervals.
+ typename LiveRangeT::iterator J = LR.begin(), E = LR.end();
+ while (J != E && VNIClasses[J->valno->id] == 0)
+ ++J;
+ for (typename LiveRangeT::iterator I = J; I != E; ++I) {
+ if (unsigned eq = VNIClasses[I->valno->id]) {
+ assert((SplitLRs[eq-1]->empty() || SplitLRs[eq-1]->expiredAt(I->start)) &&
+ "New intervals should be empty");
+ SplitLRs[eq-1]->segments.push_back(*I);
+ } else
+ *J++ = *I;
+ }
+ LR.segments.erase(J, E);
+
+ // Transfer VNInfos to their new owners and renumber them.
+ unsigned j = 0, e = LR.getNumValNums();
+ while (j != e && VNIClasses[j] == 0)
+ ++j;
+ for (unsigned i = j; i != e; ++i) {
+ VNInfo *VNI = LR.getValNumInfo(i);
+ if (unsigned eq = VNIClasses[i]) {
+ VNI->id = SplitLRs[eq-1]->getNumValNums();
+ SplitLRs[eq-1]->valnos.push_back(VNI);
+ } else {
+ VNI->id = j;
+ LR.valnos[j++] = VNI;
+ }
+ }
+ LR.valnos.resize(j);
+}
+
+} // End llvm namespace
+
+#endif
Modified: llvm/trunk/lib/CodeGen/MachineScheduler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineScheduler.cpp?rev=271345&r1=271344&r2=271345&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/MachineScheduler.cpp (original)
+++ llvm/trunk/lib/CodeGen/MachineScheduler.cpp Tue May 31 17:38:06 2016
@@ -882,16 +882,8 @@ void ScheduleDAGMILive::enterRegion(Mach
ShouldTrackPressure = SchedImpl->shouldTrackPressure();
ShouldTrackLaneMasks = SchedImpl->shouldTrackLaneMasks();
- if (ShouldTrackLaneMasks) {
- if (!ShouldTrackPressure)
- report_fatal_error("ShouldTrackLaneMasks requires ShouldTrackPressure");
- // Dead subregister defs have no users and therefore no dependencies,
- // moving them around may cause liveintervals to degrade into multiple
- // components. Change independent components to have their own vreg to avoid
- // this.
- if (!DisconnectedComponentsRenamed)
- LIS->renameDisconnectedComponents();
- }
+ assert((!ShouldTrackLaneMasks || ShouldTrackPressure) &&
+ "ShouldTrackLaneMasks requires ShouldTrackPressure");
}
// Setup the register pressure trackers for the top scheduled top and bottom
Added: llvm/trunk/lib/CodeGen/RenameIndependentSubregs.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/RenameIndependentSubregs.cpp?rev=271345&view=auto
==============================================================================
--- llvm/trunk/lib/CodeGen/RenameIndependentSubregs.cpp (added)
+++ llvm/trunk/lib/CodeGen/RenameIndependentSubregs.cpp Tue May 31 17:38:06 2016
@@ -0,0 +1,388 @@
+//===-- RenameIndependentSubregs.cpp - Live Interval Analysis -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// Rename independent subregisters looks for virtual registers with
+/// independently used subregisters and renames them to new virtual registers.
+/// Example: In the following:
+/// %vreg0:sub0<read-undef> = ...
+/// %vreg0:sub1 = ...
+/// use %vreg0:sub0
+/// %vreg0:sub0 = ...
+/// use %vreg0:sub0
+/// use %vreg0:sub1
+/// sub0 and sub1 are never used together, and we have two independent sub0
+/// definitions. This pass will rename to:
+/// %vreg0:sub0<read-undef> = ...
+/// %vreg1:sub1<read-undef> = ...
+/// use %vreg1:sub1
+/// %vreg2:sub1<read-undef> = ...
+/// use %vreg2:sub1
+/// use %vreg0:sub0
+//
+//===----------------------------------------------------------------------===//
+
+#include "LiveRangeUtils.h"
+#include "PHIEliminationUtils.h"
+#include "llvm/CodeGen/LiveInterval.h"
+#include "llvm/CodeGen/LiveIntervalAnalysis.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "rename-independent-subregs"
+
+namespace {
+
+class RenameIndependentSubregs : public MachineFunctionPass {
+public:
+ static char ID;
+ RenameIndependentSubregs() : MachineFunctionPass(ID) {}
+
+ const char *getPassName() const override {
+ return "Rename Disconnected Subregister Components";
+ }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ AU.addRequired<LiveIntervals>();
+ AU.addPreserved<LiveIntervals>();
+ AU.addRequired<SlotIndexes>();
+ AU.addPreserved<SlotIndexes>();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+private:
+ struct SubRangeInfo {
+ ConnectedVNInfoEqClasses ConEQ;
+ LiveInterval::SubRange *SR;
+ unsigned Index;
+
+ SubRangeInfo(LiveIntervals &LIS, LiveInterval::SubRange &SR,
+ unsigned Index)
+ : ConEQ(LIS), SR(&SR), Index(Index) {}
+ };
+
+ /// Split unrelated subregister components and rename them to new vregs.
+ bool renameComponents(LiveInterval &LI) const;
+
+ /// \brief Build a vector of SubRange infos and a union find set of
+ /// equivalence classes.
+ /// Returns true if more than 1 equivalence class was found.
+ bool findComponents(IntEqClasses &Classes,
+ SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
+ LiveInterval &LI) const;
+
+ /// \brief Distribute the LiveInterval segments into the new LiveIntervals
+ /// belonging to their class.
+ void distribute(const IntEqClasses &Classes,
+ const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
+ const SmallVectorImpl<LiveInterval*> &Intervals) const;
+
+ /// \brief Constructs main liverange and add missing undef+dead flags.
+ void computeMainRangesFixFlags(const IntEqClasses &Classes,
+ const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
+ const SmallVectorImpl<LiveInterval*> &Intervals) const;
+
+ /// Rewrite Machine Operands to use the new vreg belonging to their class.
+ void rewriteOperands(const IntEqClasses &Classes,
+ const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
+ const SmallVectorImpl<LiveInterval*> &Intervals) const;
+
+
+ LiveIntervals *LIS;
+ MachineRegisterInfo *MRI;
+ const TargetInstrInfo *TII;
+};
+
+} // end anonymous namespace
+
+char RenameIndependentSubregs::ID;
+
+char &llvm::RenameIndependentSubregsID = RenameIndependentSubregs::ID;
+
+INITIALIZE_PASS_BEGIN(RenameIndependentSubregs, "rename-independent-subregs",
+ "Rename Independent Subregisters", false, false)
+INITIALIZE_PASS_DEPENDENCY(SlotIndexes)
+INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
+INITIALIZE_PASS_END(RenameIndependentSubregs, "rename-independent-subregs",
+ "Rename Independent Subregisters", false, false)
+
+bool RenameIndependentSubregs::renameComponents(LiveInterval &LI) const {
+ // Shortcut: We cannot have split components with a single definition.
+ if (LI.valnos.size() < 2)
+ return false;
+
+ SmallVector<SubRangeInfo, 4> SubRangeInfos;
+ IntEqClasses Classes;
+ if (!findComponents(Classes, SubRangeInfos, LI))
+ return false;
+
+ // Create a new VReg for each class.
+ unsigned Reg = LI.reg;
+ const TargetRegisterClass *RegClass = MRI->getRegClass(Reg);
+ SmallVector<LiveInterval*, 4> Intervals;
+ Intervals.push_back(&LI);
+ DEBUG(dbgs() << PrintReg(Reg) << ": Found " << Classes.getNumClasses()
+ << " equivalence classes.\n");
+ DEBUG(dbgs() << PrintReg(Reg) << ": Splitting into newly created:");
+ for (unsigned I = 1, NumClasses = Classes.getNumClasses(); I < NumClasses;
+ ++I) {
+ unsigned NewVReg = MRI->createVirtualRegister(RegClass);
+ LiveInterval &NewLI = LIS->createEmptyInterval(NewVReg);
+ Intervals.push_back(&NewLI);
+ DEBUG(dbgs() << ' ' << PrintReg(NewVReg));
+ }
+ DEBUG(dbgs() << '\n');
+
+ rewriteOperands(Classes, SubRangeInfos, Intervals);
+ distribute(Classes, SubRangeInfos, Intervals);
+ computeMainRangesFixFlags(Classes, SubRangeInfos, Intervals);
+ return true;
+}
+
+bool RenameIndependentSubregs::findComponents(IntEqClasses &Classes,
+ SmallVectorImpl<RenameIndependentSubregs::SubRangeInfo> &SubRangeInfos,
+ LiveInterval &LI) const {
+ // First step: Create connected components for the VNInfos inside the
+ // subranges and count the global number of such components.
+ unsigned NumComponents = 0;
+ for (LiveInterval::SubRange &SR : LI.subranges()) {
+ SubRangeInfos.push_back(SubRangeInfo(*LIS, SR, NumComponents));
+ ConnectedVNInfoEqClasses &ConEQ = SubRangeInfos.back().ConEQ;
+
+ unsigned NumSubComponents = ConEQ.Classify(SR);
+ NumComponents += NumSubComponents;
+ }
+ // Shortcut: With only 1 subrange, the normal separate component tests are
+ // enough and we do not need to perform the union-find on the subregister
+ // segments.
+ if (SubRangeInfos.size() < 2)
+ return false;
+
+ // Next step: Build union-find structure over all subranges and merge classes
+ // across subranges when they are affected by the same MachineOperand.
+ const TargetRegisterInfo &TRI = *MRI->getTargetRegisterInfo();
+ Classes.grow(NumComponents);
+ unsigned Reg = LI.reg;
+ for (const MachineOperand &MO : MRI->reg_nodbg_operands(Reg)) {
+ if (!MO.isDef() && !MO.readsReg())
+ continue;
+ unsigned SubRegIdx = MO.getSubReg();
+ LaneBitmask LaneMask = TRI.getSubRegIndexLaneMask(SubRegIdx);
+ unsigned MergedID = ~0u;
+ for (RenameIndependentSubregs::SubRangeInfo &SRInfo : SubRangeInfos) {
+ const LiveInterval::SubRange &SR = *SRInfo.SR;
+ if ((SR.LaneMask & LaneMask) == 0)
+ continue;
+ SlotIndex Pos = LIS->getInstructionIndex(*MO.getParent());
+ Pos = MO.isDef() ? Pos.getRegSlot(MO.isEarlyClobber())
+ : Pos.getBaseIndex();
+ const VNInfo *VNI = SR.getVNInfoAt(Pos);
+ if (VNI == nullptr)
+ continue;
+
+ // Map to local representant ID.
+ unsigned LocalID = SRInfo.ConEQ.getEqClass(VNI);
+ // Global ID
+ unsigned ID = LocalID + SRInfo.Index;
+ // Merge other sets
+ MergedID = MergedID == ~0u ? ID : Classes.join(MergedID, ID);
+ }
+ }
+
+ // Early exit if we ended up with a single equivalence class.
+ Classes.compress();
+ unsigned NumClasses = Classes.getNumClasses();
+ return NumClasses > 1;
+}
+
+void RenameIndependentSubregs::rewriteOperands(const IntEqClasses &Classes,
+ const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
+ const SmallVectorImpl<LiveInterval*> &Intervals) const {
+ const TargetRegisterInfo &TRI = *MRI->getTargetRegisterInfo();
+ unsigned Reg = Intervals[0]->reg;;
+ for (MachineRegisterInfo::reg_nodbg_iterator I = MRI->reg_nodbg_begin(Reg),
+ E = MRI->reg_nodbg_end(); I != E; ) {
+ MachineOperand &MO = *I++;
+ if (!MO.isDef() && !MO.readsReg())
+ continue;
+
+ MachineInstr &MI = *MO.getParent();
+
+ SlotIndex Pos = LIS->getInstructionIndex(MI);
+ unsigned SubRegIdx = MO.getSubReg();
+ LaneBitmask LaneMask = TRI.getSubRegIndexLaneMask(SubRegIdx);
+
+ unsigned ID = ~0u;
+ for (const SubRangeInfo &SRInfo : SubRangeInfos) {
+ const LiveInterval::SubRange &SR = *SRInfo.SR;
+ if ((SR.LaneMask & LaneMask) == 0)
+ continue;
+ LiveRange::const_iterator I = SR.find(Pos);
+ if (I == SR.end())
+ continue;
+
+ const VNInfo &VNI = *I->valno;
+ // Map to local representant ID.
+ unsigned LocalID = SRInfo.ConEQ.getEqClass(&VNI);
+ // Global ID
+ ID = Classes[LocalID + SRInfo.Index];
+ break;
+ }
+
+ unsigned VReg = Intervals[ID]->reg;
+ MO.setReg(VReg);
+ }
+ // TODO: We could attempt to recompute new register classes while visiting
+ // the operands: Some of the split register may be fine with less constraint
+ // classes than the original vreg.
+}
+
+void RenameIndependentSubregs::distribute(const IntEqClasses &Classes,
+ const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
+ const SmallVectorImpl<LiveInterval*> &Intervals) const {
+ unsigned NumClasses = Classes.getNumClasses();
+ SmallVector<unsigned, 8> VNIMapping;
+ SmallVector<LiveInterval::SubRange*, 8> SubRanges;
+ BumpPtrAllocator &Allocator = LIS->getVNInfoAllocator();
+ for (const SubRangeInfo &SRInfo : SubRangeInfos) {
+ LiveInterval::SubRange &SR = *SRInfo.SR;
+ unsigned NumValNos = SR.valnos.size();
+ VNIMapping.clear();
+ VNIMapping.reserve(NumValNos);
+ SubRanges.clear();
+ SubRanges.resize(NumClasses-1, nullptr);
+ for (unsigned I = 0; I < NumValNos; ++I) {
+ const VNInfo &VNI = *SR.valnos[I];
+ unsigned LocalID = SRInfo.ConEQ.getEqClass(&VNI);
+ unsigned ID = Classes[LocalID + SRInfo.Index];
+ VNIMapping.push_back(ID);
+ if (ID > 0 && SubRanges[ID-1] == nullptr)
+ SubRanges[ID-1] = Intervals[ID]->createSubRange(Allocator, SR.LaneMask);
+ }
+ DistributeRange(SR, SubRanges.data(), VNIMapping);
+ }
+}
+
+static bool subRangeLiveAt(const LiveInterval &LI, SlotIndex Pos) {
+ for (const LiveInterval::SubRange &SR : LI.subranges()) {
+ if (SR.liveAt(Pos))
+ return true;
+ }
+ return false;
+}
+
+void RenameIndependentSubregs::computeMainRangesFixFlags(
+ const IntEqClasses &Classes,
+ const SmallVectorImpl<SubRangeInfo> &SubRangeInfos,
+ const SmallVectorImpl<LiveInterval*> &Intervals) const {
+ BumpPtrAllocator &Allocator = LIS->getVNInfoAllocator();
+ const SlotIndexes &Indexes = *LIS->getSlotIndexes();
+ for (size_t I = 0, E = Intervals.size(); I < E; ++I) {
+ LiveInterval &LI = *Intervals[I];
+ unsigned Reg = LI.reg;
+
+ LI.removeEmptySubRanges();
+
+ // There must be a def (or live-in) before every use. Splitting vregs may
+ // violate this principle as the splitted vreg may not have a definition on
+ // every path. Fix this by creating IMPLICIT_DEF instruction as necessary.
+ for (const LiveInterval::SubRange &SR : LI.subranges()) {
+ // Search for "PHI" value numbers in the subranges. We must find a live
+ // value in each predecessor block, add an IMPLICIT_DEF where it is
+ // missing.
+ for (unsigned I = 0; I < SR.valnos.size(); ++I) {
+ const VNInfo &VNI = *SR.valnos[I];
+ if (VNI.isUnused() || !VNI.isPHIDef())
+ continue;
+
+ SlotIndex Def = VNI.def;
+ MachineBasicBlock &MBB = *Indexes.getMBBFromIndex(Def);
+ for (MachineBasicBlock *PredMBB : MBB.predecessors()) {
+ SlotIndex PredEnd = Indexes.getMBBEndIdx(PredMBB);
+ if (subRangeLiveAt(LI, PredEnd.getPrevSlot()))
+ continue;
+
+ MachineBasicBlock::iterator InsertPos =
+ llvm::findPHICopyInsertPoint(PredMBB, &MBB, Reg);
+ const MCInstrDesc &MCDesc = TII->get(TargetOpcode::IMPLICIT_DEF);
+ MachineInstrBuilder ImpDef = BuildMI(*PredMBB, InsertPos,
+ DebugLoc(), MCDesc, Reg);
+ SlotIndex DefIdx = LIS->InsertMachineInstrInMaps(*ImpDef);
+ SlotIndex RegDefIdx = DefIdx.getRegSlot();
+ for (LiveInterval::SubRange &SR : LI.subranges()) {
+ VNInfo *SRVNI = SR.getNextValue(RegDefIdx, Allocator);
+ SR.addSegment(LiveRange::Segment(RegDefIdx, PredEnd, SRVNI));
+ }
+ }
+ }
+ }
+
+ for (MachineOperand &MO : MRI->reg_nodbg_operands(Reg)) {
+ if (!MO.isDef())
+ continue;
+ unsigned SubRegIdx = MO.getSubReg();
+ if (SubRegIdx == 0)
+ continue;
+ // After assigning the new vreg we may not have any other sublanes living
+ // in and out of the instruction anymore. We need to add new dead and
+ // undef flags in these cases.
+ if (!MO.isUndef()) {
+ SlotIndex Pos = LIS->getInstructionIndex(*MO.getParent());
+ if (!subRangeLiveAt(LI, Pos))
+ MO.setIsUndef();
+ }
+ if (!MO.isDead()) {
+ SlotIndex Pos = LIS->getInstructionIndex(*MO.getParent()).getDeadSlot();
+ if (!subRangeLiveAt(LI, Pos))
+ MO.setIsDead();
+ }
+ }
+
+ if (I == 0)
+ LI.clear();
+ LIS->constructMainRangeFromSubranges(LI);
+ }
+}
+
+bool RenameIndependentSubregs::runOnMachineFunction(MachineFunction &MF) {
+ // Skip renaming if liveness of subregister is not tracked.
+ if (!MF.getSubtarget().enableSubRegLiveness())
+ return false;
+
+ DEBUG(dbgs() << "Renaming independent subregister live ranges in "
+ << MF.getName() << '\n');
+
+ LIS = &getAnalysis<LiveIntervals>();
+ MRI = &MF.getRegInfo();
+ TII = MF.getSubtarget().getInstrInfo();
+
+ // Iterate over all vregs. Note that we query getNumVirtRegs() the newly
+ // created vregs end up with higher numbers but do not need to be visited as
+ // there can't be any further splitting.
+ bool Changed = false;
+ for (size_t I = 0, E = MRI->getNumVirtRegs(); I < E; ++I) {
+ unsigned Reg = TargetRegisterInfo::index2VirtReg(I);
+ if (!LIS->hasInterval(Reg))
+ continue;
+ LiveInterval &LI = LIS->getInterval(Reg);
+ if (!LI.hasSubRanges())
+ continue;
+
+ Changed |= renameComponents(LI);
+ }
+
+ return Changed;
+}
Modified: llvm/trunk/lib/CodeGen/TargetPassConfig.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/TargetPassConfig.cpp?rev=271345&r1=271344&r2=271345&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/TargetPassConfig.cpp (original)
+++ llvm/trunk/lib/CodeGen/TargetPassConfig.cpp Tue May 31 17:38:06 2016
@@ -775,6 +775,11 @@ void TargetPassConfig::addOptimizedRegAl
addPass(&TwoAddressInstructionPassID, false);
addPass(&RegisterCoalescerID);
+ // The machine scheduler may accidentally create disconnected components
+ // when moving subregister definitions around, avoid this by splitting them to
+ // separate vregs before. Splitting can also improve reg. allocation quality.
+ addPass(&RenameIndependentSubregsID);
+
// PreRA instruction scheduling.
addPass(&MachineSchedulerID);
Added: llvm/trunk/test/CodeGen/AMDGPU/rename-independent-subregs.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AMDGPU/rename-independent-subregs.mir?rev=271345&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AMDGPU/rename-independent-subregs.mir (added)
+++ llvm/trunk/test/CodeGen/AMDGPU/rename-independent-subregs.mir Tue May 31 17:38:06 2016
@@ -0,0 +1,30 @@
+# RUN: llc -march=amdgcn -run-pass rename-independent-subregs -o /dev/null %s 2>&1 | FileCheck %s
+--- |
+ define void @test0() { ret void }
+...
+---
+# In the test below we have two independent def+use pairs of subregister1 which
+# can be moved to a new virtual register. The third def of sub1 however is used
+# in combination with sub0 and needs to stay with the original vreg.
+# CHECK-LABEL: name: test0
+# CHECK: S_NOP 0, implicit-def undef %0:sub0
+# CHECK: S_NOP 0, implicit-def undef %2:sub1
+# CHECK: S_NOP 0, implicit %2:sub1
+# CHECK: S_NOP 0, implicit-def undef %1:sub1
+# CHECK: S_NOP 0, implicit %1:sub1
+# CHECK: S_NOP 0, implicit-def %0:sub1
+# CHECK: S_NOP 0, implicit %0
+name: test0
+isSSA: true
+registers:
+ - { id: 0, class: sreg_128 }
+body: |
+ bb.0:
+ S_NOP 0, implicit-def undef %0:sub0
+ S_NOP 0, implicit-def %0:sub1
+ S_NOP 0, implicit %0:sub1
+ S_NOP 0, implicit-def %0:sub1
+ S_NOP 0, implicit %0:sub1
+ S_NOP 0, implicit-def %0:sub1
+ S_NOP 0, implicit %0
+...
More information about the llvm-commits
mailing list