From c519d3c403986b5e91e68c3788f1485d8072392a Mon Sep 17 00:00:00 2001 From: David Green Date: Tue, 23 Apr 2019 12:11:26 +0000 Subject: [PATCH] [ARM] Update check for CBZ in Ifcvt The check for creating CBZ in constant island pass recently obtained the ability to search backwards to find a Cmp instruction. The code in IfCvt should mirror this to allow more conversions to the smaller form. The common code has been pulled out into a separate function to be shared between the two places. Differential Revision: https://reviews.llvm.org/D60090 llvm-svn: 358977 --- llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp | 58 +++++++-- llvm/lib/Target/ARM/ARMBaseInstrInfo.h | 10 ++ llvm/lib/Target/ARM/ARMConstantIslandPass.cpp | 34 +---- llvm/test/CodeGen/Thumb2/ifcvt-cbz.mir | 179 ++++++++++++++++++++++++++ 4 files changed, 238 insertions(+), 43 deletions(-) create mode 100644 llvm/test/CodeGen/Thumb2/ifcvt-cbz.mir diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp index 32c0cbd..b55af47 100644 --- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -1904,19 +1904,10 @@ isProfitableToIfCvt(MachineBasicBlock &MBB, if (!Pred->empty()) { MachineInstr *LastMI = &*Pred->rbegin(); if (LastMI->getOpcode() == ARM::t2Bcc) { - MachineBasicBlock::iterator CmpMI = LastMI; - if (CmpMI != Pred->begin()) { - --CmpMI; - if (CmpMI->getOpcode() == ARM::tCMPi8 || - CmpMI->getOpcode() == ARM::t2CMPri) { - unsigned Reg = CmpMI->getOperand(0).getReg(); - unsigned PredReg = 0; - ARMCC::CondCodes P = getInstrPredicate(*CmpMI, PredReg); - if (P == ARMCC::AL && CmpMI->getOperand(1).getImm() == 0 && - isARMLowRegister(Reg)) - return false; - } - } + const TargetRegisterInfo *TRI = &getRegisterInfo(); + MachineInstr *CmpMI = findCMPToFoldIntoCBZ(LastMI, TRI); + if (CmpMI) + return false; } } } @@ -5211,3 +5202,44 @@ ARMBaseInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const { {MO_NONLAZY, "arm-nonlazy"}}; return makeArrayRef(TargetFlags); } + +bool llvm::registerDefinedBetween(unsigned Reg, + MachineBasicBlock::iterator From, + MachineBasicBlock::iterator To, + const TargetRegisterInfo *TRI) { + for (auto I = From; I != To; ++I) + if (I->modifiesRegister(Reg, TRI)) + return true; + return false; +} + +MachineInstr *llvm::findCMPToFoldIntoCBZ(MachineInstr *Br, + const TargetRegisterInfo *TRI) { + // Search backwards to the instruction that defines CSPR. This may or not + // be a CMP, we check that after this loop. If we find another instruction + // that reads cpsr, we return nullptr. + MachineBasicBlock::iterator CmpMI = Br; + while (CmpMI != Br->getParent()->begin()) { + --CmpMI; + if (CmpMI->modifiesRegister(ARM::CPSR, TRI)) + break; + if (CmpMI->readsRegister(ARM::CPSR, TRI)) + break; + } + + // Check that this inst is a CMP r[0-7], #0 and that the register + // is not redefined between the cmp and the br. + if (CmpMI->getOpcode() != ARM::tCMPi8 && CmpMI->getOpcode() != ARM::t2CMPri) + return nullptr; + unsigned Reg = CmpMI->getOperand(0).getReg(); + unsigned PredReg = 0; + ARMCC::CondCodes Pred = getInstrPredicate(*CmpMI, PredReg); + if (Pred != ARMCC::AL || CmpMI->getOperand(1).getImm() != 0) + return nullptr; + if (!isARMLowRegister(Reg)) + return nullptr; + if (registerDefinedBetween(Reg, CmpMI->getNextNode(), Br, TRI)) + return nullptr; + + return &*CmpMI; +} diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.h b/llvm/lib/Target/ARM/ARMBaseInstrInfo.h index 24c11e4..2a14744 100644 --- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.h +++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.h @@ -567,6 +567,16 @@ bool rewriteT2FrameIndex(MachineInstr &MI, unsigned FrameRegIdx, unsigned FrameReg, int &Offset, const ARMBaseInstrInfo &TII); +/// Return true if Reg is defd between From and To +bool registerDefinedBetween(unsigned Reg, MachineBasicBlock::iterator From, + MachineBasicBlock::iterator To, + const TargetRegisterInfo *TRI); + +/// Search backwards from a tBcc to find a tCMPi8 against 0, meaning +/// we can convert them to a tCBZ or tCBNZ. Return nullptr if not found. +MachineInstr *findCMPToFoldIntoCBZ(MachineInstr *Br, + const TargetRegisterInfo *TRI); + } // end namespace llvm #endif // LLVM_LIB_TARGET_ARM_ARMBASEINSTRINFO_H diff --git a/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp b/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp index 382dc44..508f41b 100644 --- a/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp +++ b/llvm/lib/Target/ARM/ARMConstantIslandPass.cpp @@ -1838,16 +1838,6 @@ bool ARMConstantIslands::optimizeThumb2Instructions() { return MadeChange; } -static bool registerDefinedBetween(unsigned Reg, - MachineBasicBlock::iterator From, - MachineBasicBlock::iterator To, - const TargetRegisterInfo *TRI) { - for (auto I = From; I != To; ++I) - if (I->modifiesRegister(Reg, TRI)) - return true; - return false; -} - bool ARMConstantIslands::optimizeThumb2Branches() { bool MadeChange = false; @@ -1915,29 +1905,13 @@ bool ARMConstantIslands::optimizeThumb2Branches() { if (BrOffset >= DestOffset || (DestOffset - BrOffset) > 126) continue; - // Search backwards to the instruction that defines CSPR. This may or not - // be a CMP, we check that after this loop. If we find an instruction that - // reads cpsr, we need to keep the original cmp. + // Search backwards to find a tCMPi8 auto *TRI = STI->getRegisterInfo(); - MachineBasicBlock::iterator CmpMI = Br.MI; - while (CmpMI != Br.MI->getParent()->begin()) { - --CmpMI; - if (CmpMI->modifiesRegister(ARM::CPSR, TRI)) - break; - if (CmpMI->readsRegister(ARM::CPSR, TRI)) - break; - } - - // Check that this inst is a CMP r[0-7], #0 and that the register - // is not redefined between the cmp and the br. - if (CmpMI->getOpcode() != ARM::tCMPi8) + MachineInstr *CmpMI = findCMPToFoldIntoCBZ(Br.MI, TRI); + if (!CmpMI || CmpMI->getOpcode() != ARM::tCMPi8) continue; + unsigned Reg = CmpMI->getOperand(0).getReg(); - Pred = getInstrPredicate(*CmpMI, PredReg); - if (Pred != ARMCC::AL || CmpMI->getOperand(1).getImm() != 0) - continue; - if (registerDefinedBetween(Reg, CmpMI->getNextNode(), Br.MI, TRI)) - continue; // Check for Kill flags on Reg. If they are present remove them and set kill // on the new CBZ. diff --git a/llvm/test/CodeGen/Thumb2/ifcvt-cbz.mir b/llvm/test/CodeGen/Thumb2/ifcvt-cbz.mir new file mode 100644 index 0000000..b567dfc --- /dev/null +++ b/llvm/test/CodeGen/Thumb2/ifcvt-cbz.mir @@ -0,0 +1,179 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple=thumbv7m-none-eabi -run-pass=if-converter -o - %s | FileCheck %s + +--- | + define i32 @f1(i32 %x) #0 { ret i32 %x } + define i32 @f2(i32 %x) #0 { ret i32 %x } + define i32 @f3(i32 %x) #0 { ret i32 %x } + declare i32 @fn(i32 %x) #0 + + attributes #0 = { minsize nounwind optsize } + +... +--- +name: f1 +tracksRegLiveness: true +liveins: + - { reg: '$r0', virtual-reg: '' } +stack: + - { id: 0, name: '', type: spill-slot, offset: -4, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '$lr', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } + - { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '$r7', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +body: | + ; CHECK-LABEL: name: f1 + ; CHECK: bb.0: + ; CHECK: liveins: $r0, $lr, $r7 + ; CHECK: t2CMPri killed renamable $r0, 1, 14, $noreg, implicit-def $cpsr + ; CHECK: tBX_RET 1, killed $cpsr + ; CHECK: $sp = frame-setup t2STMDB_UPD $sp, 14, $noreg, killed $r7, killed $lr + ; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 8 + ; CHECK: frame-setup CFI_INSTRUCTION offset $lr, -4 + ; CHECK: frame-setup CFI_INSTRUCTION offset $r7, -8 + ; CHECK: $r0 = t2MOVi 0, 14, $noreg, $noreg + ; CHECK: tBL 14, $noreg, @fn, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit $r0, implicit-def $sp, implicit-def dead $r0 + ; CHECK: $sp = t2LDMIA_UPD $sp, 14, $noreg, def $r7, def $lr + ; CHECK: tBX_RET 14, $noreg + bb.0: + successors: %bb.1(0x40000000), %bb.2(0x40000000) + liveins: $r0, $lr, $r7 + + t2CMPri killed renamable $r0, 1, 14, $noreg, implicit-def $cpsr + t2Bcc %bb.2, 1, killed $cpsr + + bb.1: + liveins: $r7, $lr + + $sp = frame-setup t2STMDB_UPD $sp, 14, $noreg, killed $r7, killed $lr + frame-setup CFI_INSTRUCTION def_cfa_offset 8 + frame-setup CFI_INSTRUCTION offset $lr, -4 + frame-setup CFI_INSTRUCTION offset $r7, -8 + $r0 = t2MOVi 0, 14, $noreg, $noreg + tBL 14, $noreg, @fn, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit $r0, implicit-def $sp, implicit-def dead $r0 + $sp = t2LDMIA_UPD $sp, 14, $noreg, def $r7, def $lr + tBX_RET 14, $noreg + + bb.2: + liveins: $lr, $r7 + + tBX_RET 14, $noreg + +... +--- +name: f2 +tracksRegLiveness: true +liveins: + - { reg: '$r0', virtual-reg: '' } +stack: + - { id: 0, name: '', type: spill-slot, offset: -4, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '$lr', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } + - { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '$r7', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +body: | + ; CHECK-LABEL: name: f2 + ; CHECK: bb.0: + ; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000) + ; CHECK: liveins: $r0, $lr, $r7 + ; CHECK: t2CMPri killed renamable $r0, 0, 14, $noreg, implicit-def $cpsr + ; CHECK: t2Bcc %bb.2, 1, killed $cpsr + ; CHECK: bb.1: + ; CHECK: liveins: $r7, $lr + ; CHECK: $sp = frame-setup t2STMDB_UPD $sp, 14, $noreg, killed $r7, killed $lr + ; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 8 + ; CHECK: frame-setup CFI_INSTRUCTION offset $lr, -4 + ; CHECK: frame-setup CFI_INSTRUCTION offset $r7, -8 + ; CHECK: $r0 = t2MOVi 0, 14, $noreg, $noreg + ; CHECK: tBL 14, $noreg, @fn, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit $r0, implicit-def $sp, implicit-def dead $r0 + ; CHECK: $sp = t2LDMIA_UPD $sp, 14, $noreg, def $r7, def $lr + ; CHECK: tBX_RET 14, $noreg + ; CHECK: bb.2: + ; CHECK: liveins: $lr, $r7 + ; CHECK: tBX_RET 14, $noreg + bb.0: + successors: %bb.1(0x40000000), %bb.2(0x40000000) + liveins: $r0, $lr, $r7 + + t2CMPri killed renamable $r0, 0, 14, $noreg, implicit-def $cpsr + t2Bcc %bb.2, 1, killed $cpsr + + bb.1: + liveins: $r7, $lr + + $sp = frame-setup t2STMDB_UPD $sp, 14, $noreg, killed $r7, killed $lr + frame-setup CFI_INSTRUCTION def_cfa_offset 8 + frame-setup CFI_INSTRUCTION offset $lr, -4 + frame-setup CFI_INSTRUCTION offset $r7, -8 + $r0 = t2MOVi 0, 14, $noreg, $noreg + tBL 14, $noreg, @fn, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit $r0, implicit-def $sp, implicit-def dead $r0 + $sp = t2LDMIA_UPD $sp, 14, $noreg, def $r7, def $lr + tBX_RET 14, $noreg + + bb.2: + liveins: $lr, $r7 + + tBX_RET 14, $noreg + +... +--- +name: f3 +tracksRegLiveness: true +liveins: + - { reg: '$r0', virtual-reg: '' } +stack: + - { id: 0, name: '', type: spill-slot, offset: -4, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '$lr', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } + - { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '$r7', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +body: | + ; CHECK-LABEL: name: f3 + ; CHECK: bb.0: + ; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000) + ; CHECK: liveins: $r0, $lr, $r7 + ; CHECK: t2CMPri killed renamable $r0, 0, 14, $noreg, implicit-def $cpsr + ; CHECK: $r1 = t2MOVi 0, 14, $noreg, $noreg + ; CHECK: t2Bcc %bb.2, 1, killed $cpsr + ; CHECK: bb.1: + ; CHECK: liveins: $r7, $lr + ; CHECK: $sp = frame-setup t2STMDB_UPD $sp, 14, $noreg, killed $r7, killed $lr + ; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 8 + ; CHECK: frame-setup CFI_INSTRUCTION offset $lr, -4 + ; CHECK: frame-setup CFI_INSTRUCTION offset $r7, -8 + ; CHECK: $r0 = t2MOVi 0, 14, $noreg, $noreg + ; CHECK: tBL 14, $noreg, @fn, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit $r0, implicit-def $sp, implicit-def dead $r0 + ; CHECK: $sp = t2LDMIA_UPD $sp, 14, $noreg, def $r7, def $lr + ; CHECK: tBX_RET 14, $noreg + ; CHECK: bb.2: + ; CHECK: liveins: $lr, $r7 + ; CHECK: tBX_RET 14, $noreg + bb.0: + successors: %bb.1(0x40000000), %bb.2(0x40000000) + liveins: $r0, $lr, $r7 + + t2CMPri killed renamable $r0, 0, 14, $noreg, implicit-def $cpsr + $r1 = t2MOVi 0, 14, $noreg, $noreg + t2Bcc %bb.2, 1, killed $cpsr + + bb.1: + liveins: $r7, $lr + + $sp = frame-setup t2STMDB_UPD $sp, 14, $noreg, killed $r7, killed $lr + frame-setup CFI_INSTRUCTION def_cfa_offset 8 + frame-setup CFI_INSTRUCTION offset $lr, -4 + frame-setup CFI_INSTRUCTION offset $r7, -8 + $r0 = t2MOVi 0, 14, $noreg, $noreg + tBL 14, $noreg, @fn, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit $r0, implicit-def $sp, implicit-def dead $r0 + $sp = t2LDMIA_UPD $sp, 14, $noreg, def $r7, def $lr + tBX_RET 14, $noreg + + bb.2: + liveins: $lr, $r7 + + tBX_RET 14, $noreg + +... -- 2.7.4