diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp index ad77106d386c9..86bdb4c7fd24c 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -3206,6 +3206,23 @@ bool RISCVDAGToDAGISel::selectSHXADD_UWOp(SDValue N, unsigned ShAmt, return false; } +bool RISCVDAGToDAGISel::selectNegImm(SDValue N, SDValue &Val) { + if (!isa(N) || !N.hasOneUse()) + return false; + int64_t Imm = cast(N)->getSExtValue(); + if (isInt<32>(Imm)) + return false; + int OrigImmCost = RISCVMatInt::getIntMatCost(APInt(64, Imm), 64, *Subtarget, + /*CompressionCost=*/true); + int NegImmCost = RISCVMatInt::getIntMatCost(APInt(64, -Imm), 64, *Subtarget, + /*CompressionCost=*/true); + if (OrigImmCost <= NegImmCost) + return false; + + Val = selectImm(CurDAG, SDLoc(N), N->getSimpleValueType(0), -Imm, *Subtarget); + return true; +} + bool RISCVDAGToDAGISel::selectInvLogicImm(SDValue N, SDValue &Val) { if (!isa(N)) return false; diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h index 82a47a9a52501..0672b6ad8829e 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h @@ -120,6 +120,7 @@ class RISCVDAGToDAGISel : public SelectionDAGISel { return selectSHXADD_UWOp(N, ShAmt, Val); } + bool selectNegImm(SDValue N, SDValue &Val); bool selectInvLogicImm(SDValue N, SDValue &Val); bool hasAllNBitUsers(SDNode *Node, unsigned Bits, diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index baf2bae367df1..6e6877079eac3 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -2120,11 +2120,16 @@ def : Pat<(XLenVT (add GPR:$rs1, immop_oneuse:$rs2)), (ADDI (XLenVT (ADDI GPR:$rs1, (AddiPairImmLarge imm:$rs2))), (AddiPairImmSmall imm:$rs2))>; +def negImm : ComplexPattern; + let Predicates = [IsRV64] in { // Select W instructions if only the lower 32-bits of the result are used. def : Pat<(binop_allwusers GPR:$rs1, immop_oneuse:$rs2), (ADDIW (i64 (ADDIW GPR:$rs1, (AddiPairImmLarge imm:$rs2))), (AddiPairImmSmall imm:$rs2))>; + +// Select SUB if the negated constant is cheaper to materialize. +def : Pat<(i64 (add GPR:$rs1, negImm:$rs2)), (SUB GPR:$rs1, negImm:$rs2)>; } //===----------------------------------------------------------------------===// diff --git a/llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll b/llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll index 4f6555393eb03..ddcf4e1a8aa77 100644 --- a/llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll +++ b/llvm/test/CodeGen/RISCV/add-imm64-to-sub.ll @@ -5,9 +5,8 @@ define i64 @add_b31(i64 %x) { ; NOZBS-LABEL: add_b31: ; NOZBS: # %bb.0: -; NOZBS-NEXT: li a1, 1 -; NOZBS-NEXT: slli a1, a1, 31 -; NOZBS-NEXT: add a0, a0, a1 +; NOZBS-NEXT: lui a1, 524288 +; NOZBS-NEXT: sub a0, a0, a1 ; NOZBS-NEXT: ret ; ; ZBS-LABEL: add_b31: @@ -20,12 +19,18 @@ define i64 @add_b31(i64 %x) { } define i64 @add_b32(i64 %x) { -; CHECK-LABEL: add_b32: -; CHECK: # %bb.0: -; CHECK-NEXT: li a1, -1 -; CHECK-NEXT: slli a1, a1, 32 -; CHECK-NEXT: add a0, a0, a1 -; CHECK-NEXT: ret +; NOZBS-LABEL: add_b32: +; NOZBS: # %bb.0: +; NOZBS-NEXT: li a1, -1 +; NOZBS-NEXT: slli a1, a1, 32 +; NOZBS-NEXT: add a0, a0, a1 +; NOZBS-NEXT: ret +; +; ZBS-LABEL: add_b32: +; ZBS: # %bb.0: +; ZBS-NEXT: bseti a1, zero, 32 +; ZBS-NEXT: sub a0, a0, a1 +; ZBS-NEXT: ret %add = add i64 %x, -4294967296 ret i64 %add } @@ -34,9 +39,8 @@ define i64 @sub_0xffffffffff(i64 %x) { ; CHECK-LABEL: sub_0xffffffffff: ; CHECK: # %bb.0: ; CHECK-NEXT: li a1, -1 -; CHECK-NEXT: slli a1, a1, 40 -; CHECK-NEXT: addi a1, a1, 1 -; CHECK-NEXT: add a0, a0, a1 +; CHECK-NEXT: srli a1, a1, 24 +; CHECK-NEXT: sub a0, a0, a1 ; CHECK-NEXT: ret %sub = sub i64 %x, 1099511627775 ret i64 %sub