Index: llvm/include/llvm/CodeGen/ReachingDefAnalysis.h =================================================================== --- llvm/include/llvm/CodeGen/ReachingDefAnalysis.h +++ llvm/include/llvm/CodeGen/ReachingDefAnalysis.h @@ -86,13 +86,25 @@ MachineFunctionProperties getRequiredProperties() const override { return MachineFunctionProperties().set( - MachineFunctionProperties::Property::NoVRegs); + MachineFunctionProperties::Property::NoVRegs).set( + MachineFunctionProperties::Property::TracksLiveness); } /// Provides the instruction id of the closest reaching def instruction of /// PhysReg that reaches MI, relative to the begining of MI's basic block. int getReachingDef(MachineInstr *MI, int PhysReg); + /// Provides the instruction of the closest reaching def instruction of + /// PhysReg that reaches MI, relative to the begining of MI's basic block. + MachineInstr *getReachingMIDef(MachineInstr *MI, int PhysReg); + + /// Provides the MI, from the given block, corresponding to the Id or a + /// nullptr if the id does not refer to the block. + MachineInstr *getInstFromId(MachineBasicBlock *MBB, int InstId); + + /// Provides the Id for the given MI. + int getInstId(MachineInstr *MI); + /// Provides the clearance - the number of instructions since the closest /// reaching def instuction of PhysReg that reaches MI. int getClearance(MachineInstr *MI, MCPhysReg PhysReg); Index: llvm/lib/CodeGen/ReachingDefAnalysis.cpp =================================================================== --- llvm/lib/CodeGen/ReachingDefAnalysis.cpp +++ llvm/lib/CodeGen/ReachingDefAnalysis.cpp @@ -189,6 +189,33 @@ return LatestDef; } +MachineInstr* ReachingDefAnalysis::getReachingMIDef(MachineInstr *MI, int PhysReg) { + return getInstFromId(MI->getParent(), getReachingDef(MI, PhysReg)); +} + +MachineInstr *ReachingDefAnalysis::getInstFromId(MachineBasicBlock *MBB, + int InstId) { + unsigned MBBNumber = MBB->getNumber(); + assert(MBBNumber < MBBReachingDefs.size() && + "Unexpected basic block number."); + assert(InstId < static_cast(MBB->size()) && + "Unexpected instruction id."); + + if (InstId < 0) + return nullptr; + + for (auto &MI : *MBB) { + if (InstIds.count(&MI) && InstIds[&MI] == InstId) + return &MI; + } + return nullptr; +} + +int ReachingDefAnalysis::getInstId(MachineInstr *MI) { + assert(InstIds.count(MI) && "Unexpected machine instruction"); + return InstIds[MI]; +} + int ReachingDefAnalysis::getClearance(MachineInstr *MI, MCPhysReg PhysReg) { assert(InstIds.count(MI) && "Unexpected machine instuction."); return InstIds[MI] - getReachingDef(MI, PhysReg); Index: llvm/lib/Target/ARM/ARMLowOverheadLoops.cpp =================================================================== --- llvm/lib/Target/ARM/ARMLowOverheadLoops.cpp +++ llvm/lib/Target/ARM/ARMLowOverheadLoops.cpp @@ -25,6 +25,8 @@ #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/ReachingDefAnalysis.h" using namespace llvm; @@ -35,6 +37,7 @@ class ARMLowOverheadLoops : public MachineFunctionPass { MachineFunction *MF = nullptr; + ReachingDefAnalysis *RDA = nullptr; const ARMBaseInstrInfo *TII = nullptr; MachineRegisterInfo *MRI = nullptr; std::unique_ptr BBUtils = nullptr; @@ -47,6 +50,7 @@ void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); AU.addRequired(); + AU.addRequired(); MachineFunctionPass::getAnalysisUsage(AU); } @@ -54,7 +58,8 @@ MachineFunctionProperties getRequiredProperties() const override { return MachineFunctionProperties().set( - MachineFunctionProperties::Property::NoVRegs); + MachineFunctionProperties::Property::NoVRegs).set( + MachineFunctionProperties::Property::TracksLiveness); } StringRef getPassName() const override { @@ -95,7 +100,7 @@ LLVM_DEBUG(dbgs() << "ARM Loops on " << MF->getName() << " ------------- \n"); auto &MLI = getAnalysis(); - MF->getProperties().set(MachineFunctionProperties::Property::TracksLiveness); + RDA = &getAnalysis(); MRI = &MF->getRegInfo(); TII = static_cast(ST.getInstrInfo()); BBUtils = std::unique_ptr(new ARMBasicBlockUtils(*MF)); @@ -116,97 +121,63 @@ MI.getOpcode() == ARM::t2WhileLoopStart; } -template -static MachineInstr* SearchForDef(MachineInstr *Begin, T End, unsigned Reg) { - for(auto &MI : make_range(T(Begin), End)) { - for (auto &MO : MI.operands()) { - if (!MO.isReg() || !MO.isDef() || MO.getReg() != Reg) - continue; - return &MI; - } - } - return nullptr; -} - -static MachineInstr* SearchForUse(MachineInstr *Begin, - MachineBasicBlock::iterator End, - unsigned Reg) { - for(auto &MI : make_range(MachineBasicBlock::iterator(Begin), End)) { - for (auto &MO : MI.operands()) { - if (!MO.isReg() || !MO.isUse() || MO.getReg() != Reg) - continue; - return &MI; - } - } - return nullptr; -} - // Is it safe to define LR with DLS/WLS? // LR can defined if it is the operand to start, because it's the same value, // or if it's going to be equivalent to the operand to Start. MachineInstr *ARMLowOverheadLoops::IsSafeToDefineLR(MachineInstr *Start) { - auto IsMoveLR = [](MachineInstr *MI, unsigned Reg) { + // We can define LR because LR already contains the same value. + if (Start->getOperand(0).getReg() == ARM::LR) + return Start; + + unsigned CountReg = Start->getOperand(0).getReg(); + auto IsMoveLR = [&CountReg](MachineInstr *MI) { return MI->getOpcode() == ARM::tMOVr && MI->getOperand(0).getReg() == ARM::LR && - MI->getOperand(1).getReg() == Reg && + MI->getOperand(1).getReg() == CountReg && MI->getOperand(2).getImm() == ARMCC::AL; }; MachineBasicBlock *MBB = Start->getParent(); - unsigned CountReg = Start->getOperand(0).getReg(); - // Walk forward and backward in the block to find the closest instructions - // that define LR. Then also filter them out if they're not a mov lr. - MachineInstr *PredLRDef = SearchForDef(Start, MBB->rend(), ARM::LR); - if (PredLRDef && !IsMoveLR(PredLRDef, CountReg)) - PredLRDef = nullptr; - - MachineInstr *SuccLRDef = SearchForDef(Start, MBB->end(), ARM::LR); - if (SuccLRDef && !IsMoveLR(SuccLRDef, CountReg)) - SuccLRDef = nullptr; - - // We've either found one, two or none mov lr instructions... Now figure out - // if they are performing the equilvant mov that the Start instruction will. - // Do this by scanning forward and backward to see if there's a def of the - // register holding the count value. If we find a suitable def, return it as - // the insert point. Later, if InsertPt != Start, then we can remove the - // redundant instruction. - if (SuccLRDef) { - MachineBasicBlock::iterator End(SuccLRDef); - if (!SearchForDef(Start, End, CountReg)) { - return SuccLRDef; - } else - SuccLRDef = nullptr; + const int StartId = RDA->getInstId(Start); + + // Is there a (mov lr, Count) before Start? If so, and nothing else writes to + // Count before Start, we can insert at that mov. + if (MachineInstr *LRDef = RDA->getReachingMIDef(Start, ARM::LR)) { + if (IsMoveLR(LRDef)) { + const int CountDefId = RDA->getReachingDef(Start, CountReg); + const int LRDefId = RDA->getReachingDef(Start, ARM::LR); + if (CountDefId < LRDefId || CountDefId > StartId) + return LRDef; + } } - if (PredLRDef) { - MachineBasicBlock::reverse_iterator End(PredLRDef); - if (!SearchForDef(Start, End, CountReg)) { - return PredLRDef; - } else - PredLRDef = nullptr; + // Is there a (mov lr, Count) after Start? If so, and nothing else writes to + // Count after Start, we can insert at that mov. + if (MachineInstr *LRDef = RDA->getReachingMIDef(&MBB->back(), ARM::LR)) { + if (IsMoveLR(LRDef)) { + const int CountDefId = RDA->getReachingDef(LRDef, CountReg); + const int LRDefId = RDA->getReachingDef(Start, ARM::LR); + if (CountDefId > LRDefId || CountDefId < StartId) + return LRDef; + } } - // We can define LR because LR already contains the same value. - if (Start->getOperand(0).getReg() == ARM::LR) - return Start; - // We've found no suitable LR def and Start doesn't use LR directly. Can we - // just define LR anyway? + // just define LR anyway? const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); LivePhysRegs LiveRegs(*TRI); LiveRegs.addLiveOuts(*MBB); - // Not if we've haven't found a suitable mov and LR is live out. - if (LiveRegs.contains(ARM::LR)) - return nullptr; + // Yes, if LR is not live out and nothing uses LR after Start. + for (auto &MI : reverse(*MBB)) { + if (&MI == Start) + return Start; - // If LR is not live out, we can insert the instruction if nothing else - // uses LR after it. - if (!SearchForUse(Start, MBB->end(), ARM::LR)) - return Start; + LiveRegs.stepBackward(MI); + if (LiveRegs.contains(ARM::LR)) + return nullptr; + } - LLVM_DEBUG(dbgs() << "ARM Loops: Failed to find suitable insertion point for" - << " LR\n"); return nullptr; } @@ -378,18 +349,14 @@ } bool ARMLowOverheadLoops::RevertLoopDec(MachineInstr *MI, - bool AllowFlags) const { + bool SetFlags) const { LLVM_DEBUG(dbgs() << "ARM Loops: Reverting to sub: " << *MI); MachineBasicBlock *MBB = MI->getParent(); - // If nothing uses or defines CPSR between LoopDec and LoopEnd, use a t2SUBS. - bool SetFlags = false; - if (AllowFlags) { - if (auto *Def = SearchForDef(MI, MBB->end(), ARM::CPSR)) { - if (!SearchForUse(MI, MBB->end(), ARM::CPSR) && - Def->getOpcode() == ARM::t2LoopEnd) - SetFlags = true; - } + // If nothing defines CPSR between LoopDec and LoopEnd, use a t2SUBS. + if (SetFlags) { + if (RDA->getReachingDef(&MBB->back(), ARM::CPSR) > RDA->getInstId(MI)) + SetFlags = false; } MachineInstrBuilder MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), Index: llvm/test/CodeGen/ARM/O3-pipeline.ll =================================================================== --- llvm/test/CodeGen/ARM/O3-pipeline.ll +++ llvm/test/CodeGen/ARM/O3-pipeline.ll @@ -154,6 +154,7 @@ ; CHECK-NEXT: ARM constant island placement and branch shortening pass ; CHECK-NEXT: MachineDominator Tree Construction ; CHECK-NEXT: Machine Natural Loop Construction +; CHECK-NEXT: ReachingDefAnalysis ; CHECK-NEXT: ARM Low Overhead Loops pass ; CHECK-NEXT: Contiguously Lay Out Funclets ; CHECK-NEXT: StackMap Liveness Analysis Index: llvm/test/CodeGen/Thumb2/ifcvt-neon-deprecated.mir =================================================================== --- llvm/test/CodeGen/Thumb2/ifcvt-neon-deprecated.mir +++ llvm/test/CodeGen/Thumb2/ifcvt-neon-deprecated.mir @@ -1,54 +1,89 @@ -# RUN: llc -mtriple=thumbv7 -start-before=if-converter -o - %s | FileCheck %s +# RUN: llc -mtriple=thumbv7 -start-before=if-converter %s -o - | FileCheck %s + +--- | + ; ModuleID = 'vdup-test.ll' + source_filename = "vdup-test.ll" + target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" + target triple = "thumbv7" + + define arm_aapcs_vfpcc <2 x i32> @NeonVdupMul(i32 %scalar, i32 %N, <2 x i32> %vector) { + entry: + %cmp = icmp ne i32 %N, 0 + %broadcast = insertelement <2 x i32> undef, i32 %scalar, i32 0 + %dup = shufflevector <2 x i32> %broadcast, <2 x i32> undef, <2 x i32> zeroinitializer + %mul = mul <2 x i32> %dup, %vector + br i1 %cmp, label %select.end, label %select.false + + select.false: ; preds = %entry + br label %select.end + + select.end: ; preds = %entry, %select.false + %res = phi <2 x i32> [ %mul, %entry ], [ %vector, %select.false ] + ret <2 x i32> %res + } + +... --- name: NeonVdupMul +alignment: 2 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +registers: [] +liveins: + - { reg: '$r0', virtual-reg: '' } + - { reg: '$r1', virtual-reg: '' } + - { reg: '$d0', virtual-reg: '' } +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: false + stackProtector: '' + maxCallFrameSize: 0 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: [] +callSites: [] +constants: [] +machineFunctionInfo: {} body: | - bb.0: - successors: %bb.2, %bb.1 + bb.0.entry: + successors: %bb.1(0x50000000), %bb.2(0x30000000) liveins: $d0, $r0, $r1 - - t2CMPri killed $r1, 0, 14, $noreg, implicit-def $cpsr + + t2CMPri killed renamable $r1, 0, 14, $noreg, implicit-def $cpsr t2Bcc %bb.2, 0, killed $cpsr - + bb.1: + successors: %bb.2(0x80000000) liveins: $d0, $r0 - - $d16 = VDUP32d killed $r0, 14, $noreg + + renamable $d16 = VDUP32d killed renamable $r0, 14, $noreg ; Verify that the neon instructions haven't been conditionalized: ; CHECK-LABEL: NeonVdupMul ; CHECK: vdup.32 ; CHECK: vmul.i32 - $d0 = VMULv2i32 killed $d16, killed $d0, 14, $noreg - - bb.2: + renamable $d0 = VMULv2i32 killed renamable $d16, killed renamable $d0, 14, $noreg + + bb.2.select.end: liveins: $d0 - - tBX_RET 14, $noreg, implicit $d0 - -... ---- -name: NeonVmovVfpLdr -body: | - bb.0.entry: - successors: %bb.1, %bb.2 - liveins: $r0, $r1 - - t2CMPri killed $r1, 0, 14, $noreg, implicit-def $cpsr - t2Bcc %bb.2, 1, killed $cpsr - - bb.1: - $d0 = VMOVv2i32 0, 14, $noreg - tBX_RET 14, $noreg, implicit $d0 - - bb.2: - liveins: $r0 - - $d0 = VLDRD killed $r0, 0, 14, $noreg - ; Verify that the neon instruction VMOVv2i32 hasn't been conditionalized, - ; but the VLDR instruction that is available both in the VFP and Advanced - ; SIMD extensions has. - ; CHECK-LABEL: NeonVmovVfpLdr - ; CHECK-DAG: vmov.i32 d0, #0x0 - ; CHECK-DAG: vldr{{ne|eq}} d0, [r0] + tBX_RET 14, $noreg, implicit $d0 ...