diff --git a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp --- a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -313,9 +313,6 @@ bool tryInsertVectorElt(SDNode *N); - // Select special operations if node forms integer ABS pattern - bool tryABSOp(SDNode *N); - bool tryReadRegister(SDNode *N); bool tryWriteRegister(SDNode *N); @@ -3464,45 +3461,6 @@ return false; } -/// Target-specific DAG combining for ISD::SUB. -/// Target-independent combining lowers SELECT_CC nodes of the form -/// select_cc setg[ge] X, 0, X, -X -/// select_cc setgt X, -1, X, -X -/// select_cc setl[te] X, 0, -X, X -/// select_cc setlt X, 1, -X, X -/// which represent Integer ABS into: -/// Y = sra (X, size(X)-1); sub (xor (X, Y), Y) -/// ARM instruction selection detects the latter and matches it to -/// ARM::ABS or ARM::t2ABS machine node. -bool ARMDAGToDAGISel::tryABSOp(SDNode *N){ - SDValue SUBSrc0 = N->getOperand(0); - SDValue SUBSrc1 = N->getOperand(1); - EVT VT = N->getValueType(0); - - if (Subtarget->isThumb1Only()) - return false; - - if (SUBSrc0.getOpcode() != ISD::XOR || SUBSrc1.getOpcode() != ISD::SRA) - return false; - - SDValue XORSrc0 = SUBSrc0.getOperand(0); - SDValue XORSrc1 = SUBSrc0.getOperand(1); - SDValue SRASrc0 = SUBSrc1.getOperand(0); - SDValue SRASrc1 = SUBSrc1.getOperand(1); - ConstantSDNode *SRAConstant = dyn_cast(SRASrc1); - EVT XType = SRASrc0.getValueType(); - unsigned Size = XType.getSizeInBits() - 1; - - if (XORSrc1 == SUBSrc1 && XORSrc0 == SRASrc0 && XType.isInteger() && - SRAConstant != nullptr && Size == SRAConstant->getZExtValue()) { - unsigned Opcode = Subtarget->isThumb2() ? ARM::t2ABS : ARM::ABS; - CurDAG->SelectNodeTo(N, Opcode, VT, XORSrc0); - return true; - } - - return false; -} - /// We've got special pseudo-instructions for these void ARMDAGToDAGISel::SelectCMP_SWAP(SDNode *N) { unsigned Opcode; @@ -3672,12 +3630,6 @@ if (tryInlineAsm(N)) return; break; - case ISD::SUB: - // Select special operations if SUB node forms integer ABS pattern - if (tryABSOp(N)) - return; - // Other cases are autogenerated. - break; case ISD::Constant: { unsigned Val = cast(N)->getZExtValue(); // If we can't materialize the constant we need to use a literal pool diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -1131,6 +1131,9 @@ setIndexedStoreAction(ISD::POST_INC, MVT::i32, Legal); } + if (!Subtarget->isThumb1Only()) + setOperationAction(ISD::ABS, MVT::i32, Legal); + setOperationAction(ISD::SADDO, MVT::i32, Custom); setOperationAction(ISD::UADDO, MVT::i32, Custom); setOperationAction(ISD::SSUBO, MVT::i32, Custom); @@ -12022,7 +12025,9 @@ return BB; case ARM::ABS: - case ARM::t2ABS: { + case ARM::NABS: + case ARM::t2ABS: + case ARM::t2NABS: { // To insert an ABS instruction, we have to insert the // diamond control-flow pattern. The incoming instruction knows the // source vreg to test against 0, the destination vreg to set, @@ -12070,10 +12075,14 @@ .addImm(0) .add(predOps(ARMCC::AL)); - // insert a bcc with opposite CC to ARMCC::MI at the end of BB + // The condition code for ABS is MI, for NABS use GT. + bool IsNABS = MI.getOpcode() == ARM::NABS || MI.getOpcode() == ARM::t2NABS; + ARMCC::CondCodes CC = IsNABS ? ARMCC::GT : ARMCC::MI; + + // insert a bcc with opposite CC at the end of BB BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2Bcc : ARM::Bcc)).addMBB(SinkBB) - .addImm(ARMCC::getOppositeCondition(ARMCC::MI)).addReg(ARM::CPSR); + .addImm(ARMCC::getOppositeCondition(CC)).addReg(ARM::CPSR); // insert rsbri in RSBBB // Note: BCC and rsbri will be converted into predicated rsbmi diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td --- a/llvm/lib/Target/ARM/ARMInstrInfo.td +++ b/llvm/lib/Target/ARM/ARMInstrInfo.td @@ -5143,8 +5143,11 @@ let usesCustomInserter = 1, Defs = [CPSR], hasNoSchedulingInfo = 1 in { // Pseudo instruction that combines movs + predicated rsbmi - // to implement integer ABS - def ABS : ARMPseudoInst<(outs GPR:$dst), (ins GPR:$src), 8, NoItinerary, []>; + // to implement integer ABS. Or movs + predicated rsbgt for NABS. + def ABS : ARMPseudoInst<(outs GPR:$dst), (ins GPR:$src), 8, NoItinerary, + [(set GPR:$dst, (abs GPR:$src))]>; + def NABS : ARMPseudoInst<(outs GPR:$dst), (ins GPR:$src), 8, NoItinerary, + [(set GPR:$dst, (ineg (abs GPR:$src)))]>; } let usesCustomInserter = 1, Defs = [CPSR], hasNoSchedulingInfo = 1 in { diff --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td --- a/llvm/lib/Target/ARM/ARMInstrThumb2.td +++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td @@ -4286,10 +4286,14 @@ Requires<[IsThumb2]>; // Pseudo instruction that combines movs + predicated rsbmi -// to implement integer ABS +// to implement integer ABS. Or movs + predicated rsbgt for NABS. let usesCustomInserter = 1, Defs = [CPSR], hasNoSchedulingInfo = 1 in { def t2ABS : PseudoInst<(outs rGPR:$dst), (ins rGPR:$src), - NoItinerary, []>, Requires<[IsThumb2]>; + NoItinerary, [(set rGPR:$dst, (abs rGPR:$src))]>, + Requires<[IsThumb2]>; +def t2NABS : PseudoInst<(outs rGPR:$dst), (ins rGPR:$src), + NoItinerary, [(set rGPR:$dst, (ineg (abs rGPR:$src)))]>, + Requires<[IsThumb2]>; } //===----------------------------------------------------------------------===// diff --git a/llvm/test/CodeGen/ARM/iabs.ll b/llvm/test/CodeGen/ARM/iabs.ll --- a/llvm/test/CodeGen/ARM/iabs.ll +++ b/llvm/test/CodeGen/ARM/iabs.ll @@ -46,3 +46,15 @@ %abs = select i1 %b, i64 %a, i64 %tmp1neg ret i64 %abs } + +define i32 @test4(i32 %a) { +; CHECK-LABEL: test4: +; CHECK: @ %bb.0: +; CHECK-NEXT: cmp r0, #0 +; CHECK-NEXT: rsbgt r0, r0, #0 +; CHECK-NEXT: bx lr + %tmp1neg = sub i32 0, %a + %b = icmp sgt i32 %a, -1 + %abs = select i1 %b, i32 %tmp1neg, i32 %a + ret i32 %abs +} diff --git a/llvm/test/CodeGen/Thumb2/abs.ll b/llvm/test/CodeGen/Thumb2/abs.ll --- a/llvm/test/CodeGen/Thumb2/abs.ll +++ b/llvm/test/CodeGen/Thumb2/abs.ll @@ -41,8 +41,9 @@ ; ; CHECKT2-LABEL: neg_abs32: ; CHECKT2: @ %bb.0: -; CHECKT2-NEXT: eor.w r1, r0, r0, asr #31 -; CHECKT2-NEXT: rsb r0, r1, r0, asr #31 +; CHECKT2-NEXT: cmp r0, #0 +; CHECKT2-NEXT: it gt +; CHECKT2-NEXT: rsbgt r0, r0, #0 ; CHECKT2-NEXT: bx lr %abs = tail call i32 @llvm.abs.i32(i32 %x, i1 true) %neg = sub nsw i32 0, %abs