From a6ef55bfe256fa5686d17a051ca95b2d453eca55 Mon Sep 17 00:00:00 2001 From: Diana Picus Date: Fri, 14 Jul 2017 09:46:06 +0000 Subject: [PATCH] [ARM] GlobalISel: Support G_BRCOND Insert a TSTri to set the flags and a Bcc to branch based on their values. This is a bit inefficient in the (common) cases where the condition for the branch comes from a compare right before the branch, since we set the flags both as part of the compare lowering and as part of the branch lowering. We're going to live with that until we settle on a principled way to handle this kind of situation, which occurs with other patterns as well (combines might be the way forward here). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@308009 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMInstructionSelector.cpp | 23 ++++++++++++ lib/Target/ARM/ARMLegalizerInfo.cpp | 2 ++ lib/Target/ARM/ARMRegisterBankInfo.cpp | 4 +++ .../ARM/GlobalISel/arm-instruction-select.mir | 30 ++++++++++++---- test/CodeGen/ARM/GlobalISel/arm-isel.ll | 28 +++++++++++++++ test/CodeGen/ARM/GlobalISel/arm-legalizer.mir | 36 +++++++++++++++++++ .../ARM/GlobalISel/arm-regbankselect.mir | 18 +++++++--- 7 files changed, 131 insertions(+), 10 deletions(-) diff --git a/lib/Target/ARM/ARMInstructionSelector.cpp b/lib/Target/ARM/ARMInstructionSelector.cpp index 29ef69ad001..faed6b867e2 100644 --- a/lib/Target/ARM/ARMInstructionSelector.cpp +++ b/lib/Target/ARM/ARMInstructionSelector.cpp @@ -722,6 +722,29 @@ bool ARMInstructionSelector::select(MachineInstr &I) const { return false; break; } + case G_BRCOND: { + if (!validReg(MRI, I.getOperand(0).getReg(), 1, ARM::GPRRegBankID)) { + DEBUG(dbgs() << "Unsupported condition register for G_BRCOND"); + return false; + } + + // Set the flags. + auto Test = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(ARM::TSTri)) + .addReg(I.getOperand(0).getReg()) + .addImm(1) + .add(predOps(ARMCC::AL)); + if (!constrainSelectedInstRegOperands(*Test, TII, TRI, RBI)) + return false; + + // Branch conditionally. + auto Branch = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(ARM::Bcc)) + .add(I.getOperand(1)) + .add(predOps(ARMCC::EQ, ARM::CPSR)); + if (!constrainSelectedInstRegOperands(*Branch, TII, TRI, RBI)) + return false; + I.eraseFromParent(); + return true; + } default: return false; } diff --git a/lib/Target/ARM/ARMLegalizerInfo.cpp b/lib/Target/ARM/ARMLegalizerInfo.cpp index f23e62595d2..4863499e214 100644 --- a/lib/Target/ARM/ARMLegalizerInfo.cpp +++ b/lib/Target/ARM/ARMLegalizerInfo.cpp @@ -88,6 +88,8 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) { setAction({G_SELECT, p0}, Legal); setAction({G_SELECT, 1, s1}, Legal); + setAction({G_BRCOND, s1}, Legal); + setAction({G_CONSTANT, s32}, Legal); for (auto Ty : {s1, s8, s16}) setAction({G_CONSTANT, Ty}, WidenScalar); diff --git a/lib/Target/ARM/ARMRegisterBankInfo.cpp b/lib/Target/ARM/ARMRegisterBankInfo.cpp index 6e93aafc2ad..84493023589 100644 --- a/lib/Target/ARM/ARMRegisterBankInfo.cpp +++ b/lib/Target/ARM/ARMRegisterBankInfo.cpp @@ -334,6 +334,10 @@ ARMRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { case G_BR: OperandsMapping = getOperandsMapping({nullptr}); break; + case G_BRCOND: + OperandsMapping = + getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], nullptr}); + break; default: return getInvalidInstructionMapping(); } diff --git a/test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir b/test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir index 3870b58a7a0..0e3ef479bc3 100644 --- a/test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir +++ b/test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir @@ -1181,17 +1181,35 @@ legalized: true regBankSelected: true selected: false # CHECK: selected: true +registers: + - { id: 0, class: gprb } body: | - ; CHECK: bb.0 bb.0: - successors: %bb.1(0x80000000) + ; CHECK: bb.0 + successors: %bb.1(0x40000000), %bb.2(0x40000000) + liveins: %r0 + + %0(s1) = COPY %r0 + ; CHECK: [[COND:%[0-9]+]] = COPY %r0 + + G_BRCOND %0(s1), %bb.1 + ; CHECK: TSTri [[COND]], 1, 14, _, implicit-def %cpsr + ; CHECK: Bcc %bb.1, 0, %cpsr + G_BR %bb.2 + ; CHECK: B %bb.2 - ; CHECK: bb.1 bb.1: - successors: %bb.1(0x80000000) + ; CHECK: bb.1 + successors: %bb.2(0x80000000) + + G_BR %bb.2 + ; CHECK: B %bb.2 - ; CHECK: B %bb.1 - G_BR %bb.1 + bb.2: + ; CHECK: bb.2 + + BX_RET 14, _ + ; CHECK: BX_RET 14, _ ... --- name: test_soft_fp_double diff --git a/test/CodeGen/ARM/GlobalISel/arm-isel.ll b/test/CodeGen/ARM/GlobalISel/arm-isel.ll index b763b48c474..419bcf71c10 100644 --- a/test/CodeGen/ARM/GlobalISel/arm-isel.ll +++ b/test/CodeGen/ARM/GlobalISel/arm-isel.ll @@ -431,3 +431,31 @@ entry: infinite: br label %infinite } + +declare arm_aapcscc void @brcond1() +declare arm_aapcscc void @brcond2() + +define arm_aapcscc void @test_brcond(i32 %n) { +; CHECK-LABEL: test_brcond +; CHECK: cmp r0 +; CHECK-NEXT: movgt [[RCMP:r[0-9]+]], #1 +; CHECK: tst [[RCMP]], #1 +; CHECK-NEXT: bne [[FALSE:.L[[:alnum:]_]+]] +; CHECK: blx brcond1 +; CHECK: [[FALSE]]: +; CHECK: blx brcond2 +entry: + %cmp = icmp sgt i32 %n, 0 + br i1 %cmp, label %if.true, label %if.false + +if.true: + call arm_aapcscc void @brcond1() + br label %if.end + +if.false: + call arm_aapcscc void @brcond2() + br label %if.end + +if.end: + ret void +} diff --git a/test/CodeGen/ARM/GlobalISel/arm-legalizer.mir b/test/CodeGen/ARM/GlobalISel/arm-legalizer.mir index 4575341dfc2..616f29d3b06 100644 --- a/test/CodeGen/ARM/GlobalISel/arm-legalizer.mir +++ b/test/CodeGen/ARM/GlobalISel/arm-legalizer.mir @@ -42,6 +42,8 @@ define void @test_select_s32() { ret void } define void @test_select_ptr() { ret void } + define void @test_brcond() { ret void } + define void @test_fadd_s32() #0 { ret void } define void @test_fadd_s64() #0 { ret void } @@ -863,6 +865,40 @@ body: | BX_RET 14, _, implicit %r0 ... --- +name: test_brcond +# CHECK-LABEL: name: test_brcond +legalized: false +# CHECK: legalized: true +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +body: | + bb.0: + successors: %bb.1(0x40000000), %bb.2(0x40000000) + liveins: %r0, %r1 + + %0(s32) = COPY %r0 + %1(s32) = COPY %r1 + %2(s1) = G_ICMP intpred(sgt), %0(s32), %1 + G_BRCOND %2(s1), %bb.1 + ; G_BRCOND with s1 is legal, so we should find it unchanged in the output + ; CHECK: G_BRCOND {{%[0-9]+}}(s1), %bb.1 + G_BR %bb.2 + + bb.1: + %r0 = COPY %1(s32) + BX_RET 14, _, implicit %r0 + + bb.2: + %r0 = COPY %0(s32) + BX_RET 14, _, implicit %r0 + +... +--- name: test_fadd_s32 # CHECK-LABEL: name: test_fadd_s32 legalized: false diff --git a/test/CodeGen/ARM/GlobalISel/arm-regbankselect.mir b/test/CodeGen/ARM/GlobalISel/arm-regbankselect.mir index 28053ed4596..638c6e62092 100644 --- a/test/CodeGen/ARM/GlobalISel/arm-regbankselect.mir +++ b/test/CodeGen/ARM/GlobalISel/arm-regbankselect.mir @@ -837,16 +837,26 @@ name: test_br legalized: true regBankSelected: false # CHECK: regBankSelected: true -# There aren't any registers to map, but make sure we don't crash. selected: false +registers: + - { id: 0, class: _ } +# CHECK: { id: 0, class: gprb, preferred-register: '' } +# Check that we map the condition of the G_BRCOND into the GPR. +# For the G_BR, there are no registers to map, but make sure we don't crash. body: | bb.0: - successors: %bb.1(0x80000000) + successors: %bb.1(0x40000000), %bb.2(0x40000000) + liveins: %r0 + + %0(s1) = COPY %r0 + G_BRCOND %0(s1), %bb.1 + G_BR %bb.2 bb.1: - successors: %bb.1(0x80000000) + BX_RET 14, _ - G_BR %bb.1 + bb.2: + BX_RET 14, _ ... --- -- 2.49.0