bool tryInlineAsm(SDNode *N);
void SelectConcatVector(SDNode *N);
- void SelectCMPZ(SDNode *N, bool &SwitchEQNEToPLMI);
-
+
bool trySMLAWSMULW(SDNode *N);
void SelectCMP_SWAP(SDNode *N);
ReplaceNode(N, createDRegPairNode(VT, N->getOperand(0), N->getOperand(1)));
}
-static Optional<std::pair<unsigned, unsigned>>
-getContiguousRangeOfSetBits(const APInt &A) {
- unsigned FirstOne = A.getBitWidth() - A.countLeadingZeros() - 1;
- unsigned LastOne = A.countTrailingZeros();
- if (A.countPopulation() != (FirstOne - LastOne + 1))
- return Optional<std::pair<unsigned,unsigned>>();
- return std::make_pair(FirstOne, LastOne);
-}
-
-void ARMDAGToDAGISel::SelectCMPZ(SDNode *N, bool &SwitchEQNEToPLMI) {
- assert(N->getOpcode() == ARMISD::CMPZ);
- SwitchEQNEToPLMI = false;
-
- if (!Subtarget->isThumb())
- // FIXME: Work out whether it is profitable to do this in A32 mode - LSL and
- // LSR don't exist as standalone instructions - they need the barrel shifter.
- return;
- // select (cmpz (and X, C), #0) -> (LSLS X) or (LSRS X) or (LSRS (LSLS X))
- SDValue And = N->getOperand(0);
- SDValue Zero = N->getOperand(1);
- if (!isa<ConstantSDNode>(Zero) || !cast<ConstantSDNode>(Zero)->isNullValue() ||
- And->getOpcode() != ISD::AND)
- return;
- SDValue X = And.getOperand(0);
- auto C = dyn_cast<ConstantSDNode>(And.getOperand(1));
-
- if (!C || !X->hasOneUse())
- return;
- auto Range = getContiguousRangeOfSetBits(C->getAPIntValue());
- if (!Range)
- return;
-
- // There are several ways to lower this:
- SDNode *NewN;
- SDLoc dl(N);
-
- auto EmitShift = [&](unsigned Opc, SDValue Src, unsigned Imm) -> SDNode* {
- if (Subtarget->isThumb2()) {
- Opc = (Opc == ARM::tLSLri) ? ARM::t2LSLri : ARM::t2LSRri;
- SDValue Ops[] = { Src, CurDAG->getTargetConstant(Imm, dl, MVT::i32),
- getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
- CurDAG->getRegister(0, MVT::i32) };
- return CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops);
- } else {
- SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32), Src,
- CurDAG->getTargetConstant(Imm, dl, MVT::i32),
- getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32)};
- return CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops);
- }
- };
-
- if (Range->second == 0) {
- // 1. Mask includes the LSB -> Simply shift the top N bits off
- NewN = EmitShift(ARM::tLSLri, X, 31 - Range->first);
- ReplaceNode(And.getNode(), NewN);
- } else if (Range->first == 31) {
- // 2. Mask includes the MSB -> Simply shift the bottom N bits off
- NewN = EmitShift(ARM::tLSRri, X, Range->second);
- ReplaceNode(And.getNode(), NewN);
- } else if (Range->first == Range->second) {
- // 3. Only one bit is set. We can shift this into the sign bit and use a
- // PL/MI comparison.
- NewN = EmitShift(ARM::tLSLri, X, 31 - Range->first);
- ReplaceNode(And.getNode(), NewN);
-
- SwitchEQNEToPLMI = true;
- } else if (!Subtarget->hasV6T2Ops()) {
- // 4. Do a double shift to clear bottom and top bits, but only in
- // thumb-1 mode as in thumb-2 we can use UBFX.
- NewN = EmitShift(ARM::tLSLri, X, 31 - Range->first);
- NewN = EmitShift(ARM::tLSRri, SDValue(NewN, 0),
- Range->second + (31 - Range->first));
- ReplaceNode(And.getNode(), NewN);
- }
-
-}
-
void ARMDAGToDAGISel::Select(SDNode *N) {
SDLoc dl(N);
return;
}
}
-
break;
}
case ARMISD::VMOVRRD:
assert(N2.getOpcode() == ISD::Constant);
assert(N3.getOpcode() == ISD::Register);
- unsigned CC = (unsigned) cast<ConstantSDNode>(N2)->getZExtValue();
-
- if (InFlag.getOpcode() == ARMISD::CMPZ) {
- bool SwitchEQNEToPLMI;
- SelectCMPZ(InFlag.getNode(), SwitchEQNEToPLMI);
- InFlag = N->getOperand(4);
-
- if (SwitchEQNEToPLMI) {
- switch ((ARMCC::CondCodes)CC) {
- default: llvm_unreachable("CMPZ must be either NE or EQ!");
- case ARMCC::NE:
- CC = (unsigned)ARMCC::MI;
- break;
- case ARMCC::EQ:
- CC = (unsigned)ARMCC::PL;
- break;
- }
- }
- }
-
- SDValue Tmp2 = CurDAG->getTargetConstant(CC, dl, MVT::i32);
+ SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
+ cast<ConstantSDNode>(N2)->getZExtValue()), dl,
+ MVT::i32);
SDValue Ops[] = { N1, Tmp2, N3, Chain, InFlag };
SDNode *ResNode = CurDAG->getMachineNode(Opc, dl, MVT::Other,
MVT::Glue, Ops);
// Other cases are autogenerated.
break;
}
-
- case ARMISD::CMOV: {
- SDValue InFlag = N->getOperand(4);
-
- if (InFlag.getOpcode() == ARMISD::CMPZ) {
- bool SwitchEQNEToPLMI;
- SelectCMPZ(InFlag.getNode(), SwitchEQNEToPLMI);
-
- if (SwitchEQNEToPLMI) {
- SDValue ARMcc = N->getOperand(2);
- ARMCC::CondCodes CC =
- (ARMCC::CondCodes)cast<ConstantSDNode>(ARMcc)->getZExtValue();
-
- switch (CC) {
- default: llvm_unreachable("CMPZ must be either NE or EQ!");
- case ARMCC::NE:
- CC = ARMCC::MI;
- break;
- case ARMCC::EQ:
- CC = ARMCC::PL;
- break;
- }
- SDValue NewARMcc = CurDAG->getConstant((unsigned)CC, dl, MVT::i32);
- SDValue Ops[] = {N->getOperand(0), N->getOperand(1), NewARMcc,
- N->getOperand(3), N->getOperand(4)};
- CurDAG->MorphNodeTo(N, ARMISD::CMOV, CurDAG->getVTList(MVT::i32),
- Ops);
- }
-
- }
- // Other cases are autogenerated.
- break;
- }
case ARMISD::VZIP: {
unsigned Opc = 0;
+++ /dev/null
-; RUN: llc -mtriple=thumbv7m-linux-gnu < %s | FileCheck %s --check-prefix=CHECK --check-prefix=T2
-; RUN: llc -mtriple=thumbv6m-linux-gnu < %s | FileCheck %s --check-prefix=CHECK --check-prefix=T1
-
-; CHECK-LABEL: single_bit:
-; CHECK: lsls r0, r0, #23
-; T2-NEXT: mov
-; T2-NEXT: it
-; T1-NEXT: bmi
-define i32 @single_bit(i32 %p) {
- %a = and i32 %p, 256
- %b = icmp eq i32 %a, 0
- br i1 %b, label %true, label %false
-
-true:
- ret i32 1
-
-false:
- ret i32 2
-}
-
-; CHECK-LABEL: multi_bit_lsb_ubfx:
-; CHECK: lsls r0, r0, #24
-; T2-NEXT: mov
-; T2-NEXT: it
-; T1-NEXT: beq
-define i32 @multi_bit_lsb_ubfx(i32 %p) {
- %a = and i32 %p, 255
- %b = icmp eq i32 %a, 0
- br i1 %b, label %true, label %false
-
-true:
- ret i32 1
-
-false:
- ret i32 2
-}
-
-; CHECK-LABEL: multi_bit_msb:
-; CHECK: lsrs r0, r0, #24
-; T2-NEXT: mov
-; T2-NEXT: it
-; T1-NEXT: beq
-define i32 @multi_bit_msb(i32 %p) {
- %a = and i32 %p, 4278190080 ; 0xff000000
- %b = icmp eq i32 %a, 0
- br i1 %b, label %true, label %false
-
-true:
- ret i32 1
-
-false:
- ret i32 2
-}
-
-; CHECK-LABEL: multi_bit_nosb:
-; T1: lsls r0, r0, #8
-; T1-NEXT: lsrs r0, r0, #24
-; T2: tst.w
-; T2-NEXT: it
-; T1-NEXT: beq
-define i32 @multi_bit_nosb(i32 %p) {
- %a = and i32 %p, 16711680 ; 0x00ff0000
- %b = icmp eq i32 %a, 0
- br i1 %b, label %true, label %false
-
-true:
- ret i32 1
-
-false:
- ret i32 2
-}
define float @select_f(float %a, float %b, i1 %c) {
; CHECK-LABEL: select_f:
-; NONE: lsls r2, r2, #31
+; NONE: tst.w r2, #1
; NONE: moveq r0, r1
-; HARD: lsls r0, r0, #31
+; HARD: tst.w r0, #1
; VFP4-ALL: vmovne.f32 s1, s0
; VFP4-ALL: vmov.f32 s0, s1
; FP-ARMv8: vseleq.f32 s0, s1, s0
define double @select_d(double %a, double %b, i1 %c) {
; CHECK-LABEL: select_d:
-; NONE: ldr{{(.w)?}} [[REG:r[0-9]+]], [sp]
-; NONE: lsls{{(.w)?}} [[REG]], [[REG]], #31
+; NONE: ldr.w [[REG:r[0-9]+]], [sp]
+; NONE: ands [[REG]], [[REG]], #1
; NONE: moveq r0, r2
; NONE: moveq r1, r3
-; SP: lsls r0, r0, #31
+; SP: ands r0, r0, #1
; SP-DAG: vmov [[ALO:r[0-9]+]], [[AHI:r[0-9]+]], d0
; SP-DAG: vmov [[BLO:r[0-9]+]], [[BHI:r[0-9]+]], d1
; SP: itt ne
; SP-DAG: movne [[BLO]], [[ALO]]
; SP-DAG: movne [[BHI]], [[AHI]]
; SP: vmov d0, [[BLO]], [[BHI]]
-; DP: lsls r0, r0, #31
+; DP: tst.w r0, #1
; VFP4-DP: vmovne.f64 d1, d0
; VFP4-DP: vmov.f64 d0, d1
; FP-ARMV8: vseleq.f64 d0, d1, d0