diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp index fa3357f3eacc3..b33d58d177457 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -3236,6 +3236,35 @@ bool RISCVDAGToDAGISel::selectSHXADD_UWOp(SDValue N, unsigned ShAmt, return false; } +bool RISCVDAGToDAGISel::selectInvLogicImm(SDValue N, SDValue &Val) { + if (!isa(N)) + return false; + + int64_t Imm = cast(N)->getSExtValue(); + if ((Imm & 0xfff) != 0xfff || Imm == -1) + return false; + + for (const SDNode *U : N->users()) { + if (!ISD::isBitwiseLogicOp(U->getOpcode())) + return false; + } + + // For 32-bit signed constants we already know it's a win: LUI+ADDI vs LUI. + // For 64-bit constants, the instruction sequences get complex, + // so we select inverted only if it's cheaper. + if (!isInt<32>(Imm)) { + 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; +} + static bool vectorPseudoHasAllNBitUsers(SDNode *User, unsigned UserOpNo, unsigned Bits, const TargetInstrInfo *TII) { diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h index 2e738d8d25a6d..e75aff7eda993 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h @@ -119,6 +119,8 @@ class RISCVDAGToDAGISel : public SelectionDAGISel { return selectSHXADD_UWOp(N, ShAmt, Val); } + bool selectInvLogicImm(SDValue N, SDValue &Val); + bool hasAllNBitUsers(SDNode *Node, unsigned Bits, const unsigned Depth = 0) const; bool hasAllBUsers(SDNode *Node) const { return hasAllNBitUsers(Node, 8); } diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td index a78091cd02a35..124caa3b69d31 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td @@ -475,10 +475,16 @@ def : InstAlias<"zext.h $rd, $rs", (PACKW GPR:$rd, GPR:$rs, X0)>; // Codegen patterns //===----------------------------------------------------------------------===// +def invLogicImm : ComplexPattern; + let Predicates = [HasStdExtZbbOrZbkb] in { def : Pat<(XLenVT (and GPR:$rs1, (not GPR:$rs2))), (ANDN GPR:$rs1, GPR:$rs2)>; def : Pat<(XLenVT (or GPR:$rs1, (not GPR:$rs2))), (ORN GPR:$rs1, GPR:$rs2)>; def : Pat<(XLenVT (xor GPR:$rs1, (not GPR:$rs2))), (XNOR GPR:$rs1, GPR:$rs2)>; + +def : Pat<(XLenVT (and GPR:$rs1, invLogicImm:$rs2)), (ANDN GPR:$rs1, invLogicImm:$rs2)>; +def : Pat<(XLenVT (or GPR:$rs1, invLogicImm:$rs2)), (ORN GPR:$rs1, invLogicImm:$rs2)>; +def : Pat<(XLenVT (xor GPR:$rs1, invLogicImm:$rs2)), (XNOR GPR:$rs1, invLogicImm:$rs2)>; } // Predicates = [HasStdExtZbbOrZbkb] let Predicates = [HasStdExtZbbOrZbkb] in { diff --git a/llvm/test/CodeGen/RISCV/pr84653_pr85190.ll b/llvm/test/CodeGen/RISCV/pr84653_pr85190.ll index b1bba5fdc9211..30a9355734772 100644 --- a/llvm/test/CodeGen/RISCV/pr84653_pr85190.ll +++ b/llvm/test/CodeGen/RISCV/pr84653_pr85190.ll @@ -21,8 +21,7 @@ define i1 @pr84653(i32 %x) { ; CHECK-ZBB: # %bb.0: ; CHECK-ZBB-NEXT: sext.w a1, a0 ; CHECK-ZBB-NEXT: lui a2, 524288 -; CHECK-ZBB-NEXT: addi a2, a2, -1 -; CHECK-ZBB-NEXT: xor a0, a0, a2 +; CHECK-ZBB-NEXT: xnor a0, a0, a2 ; CHECK-ZBB-NEXT: sext.w a0, a0 ; CHECK-ZBB-NEXT: max a0, a0, zero ; CHECK-ZBB-NEXT: slt a0, a0, a1 @@ -82,8 +81,7 @@ define i1 @select_to_or(i32 %x) { ; CHECK-ZBB: # %bb.0: ; CHECK-ZBB-NEXT: sext.w a1, a0 ; CHECK-ZBB-NEXT: lui a2, 524288 -; CHECK-ZBB-NEXT: addi a2, a2, -1 -; CHECK-ZBB-NEXT: xor a0, a0, a2 +; CHECK-ZBB-NEXT: xnor a0, a0, a2 ; CHECK-ZBB-NEXT: sext.w a0, a0 ; CHECK-ZBB-NEXT: min a0, a0, zero ; CHECK-ZBB-NEXT: slt a0, a0, a1 diff --git a/llvm/test/CodeGen/RISCV/zbb-logic-neg-imm.ll b/llvm/test/CodeGen/RISCV/zbb-logic-neg-imm.ll index 87e72c28a9965..f1e4bd09fcb92 100644 --- a/llvm/test/CodeGen/RISCV/zbb-logic-neg-imm.ll +++ b/llvm/test/CodeGen/RISCV/zbb-logic-neg-imm.ll @@ -9,37 +9,21 @@ ; RUN: | FileCheck %s --check-prefixes=CHECK,RV64,ZBS define i32 @and0xabcdefff(i32 %x) { -; RV32-LABEL: and0xabcdefff: -; RV32: # %bb.0: -; RV32-NEXT: lui a1, 703711 -; RV32-NEXT: addi a1, a1, -1 -; RV32-NEXT: and a0, a0, a1 -; RV32-NEXT: ret -; -; RV64-LABEL: and0xabcdefff: -; RV64: # %bb.0: -; RV64-NEXT: lui a1, 703711 -; RV64-NEXT: addiw a1, a1, -1 -; RV64-NEXT: and a0, a0, a1 -; RV64-NEXT: ret +; CHECK-LABEL: and0xabcdefff: +; CHECK: # %bb.0: +; CHECK-NEXT: lui a1, 344865 +; CHECK-NEXT: andn a0, a0, a1 +; CHECK-NEXT: ret %and = and i32 %x, -1412567041 ret i32 %and } define i32 @orlow13(i32 %x) { -; RV32-LABEL: orlow13: -; RV32: # %bb.0: -; RV32-NEXT: lui a1, 2 -; RV32-NEXT: addi a1, a1, -1 -; RV32-NEXT: or a0, a0, a1 -; RV32-NEXT: ret -; -; RV64-LABEL: orlow13: -; RV64: # %bb.0: -; RV64-NEXT: lui a1, 2 -; RV64-NEXT: addiw a1, a1, -1 -; RV64-NEXT: or a0, a0, a1 -; RV64-NEXT: ret +; CHECK-LABEL: orlow13: +; CHECK: # %bb.0: +; CHECK-NEXT: lui a1, 1048574 +; CHECK-NEXT: orn a0, a0, a1 +; CHECK-NEXT: ret %or = or i32 %x, 8191 ret i32 %or } @@ -47,53 +31,35 @@ define i32 @orlow13(i32 %x) { define i64 @orlow24(i64 %x) { ; RV32-LABEL: orlow24: ; RV32: # %bb.0: -; RV32-NEXT: lui a2, 4096 -; RV32-NEXT: addi a2, a2, -1 -; RV32-NEXT: or a0, a0, a2 +; RV32-NEXT: lui a2, 1044480 +; RV32-NEXT: orn a0, a0, a2 ; RV32-NEXT: ret ; ; RV64-LABEL: orlow24: ; RV64: # %bb.0: -; RV64-NEXT: lui a1, 4096 -; RV64-NEXT: addiw a1, a1, -1 -; RV64-NEXT: or a0, a0, a1 +; RV64-NEXT: lui a1, 1044480 +; RV64-NEXT: orn a0, a0, a1 ; RV64-NEXT: ret %or = or i64 %x, 16777215 ret i64 %or } define i32 @xorlow16(i32 %x) { -; RV32-LABEL: xorlow16: -; RV32: # %bb.0: -; RV32-NEXT: lui a1, 16 -; RV32-NEXT: addi a1, a1, -1 -; RV32-NEXT: xor a0, a0, a1 -; RV32-NEXT: ret -; -; RV64-LABEL: xorlow16: -; RV64: # %bb.0: -; RV64-NEXT: lui a1, 16 -; RV64-NEXT: addiw a1, a1, -1 -; RV64-NEXT: xor a0, a0, a1 -; RV64-NEXT: ret +; CHECK-LABEL: xorlow16: +; CHECK: # %bb.0: +; CHECK-NEXT: lui a1, 1048560 +; CHECK-NEXT: xnor a0, a0, a1 +; CHECK-NEXT: ret %xor = xor i32 %x, 65535 ret i32 %xor } define i32 @xorlow31(i32 %x) { -; RV32-LABEL: xorlow31: -; RV32: # %bb.0: -; RV32-NEXT: lui a1, 524288 -; RV32-NEXT: addi a1, a1, -1 -; RV32-NEXT: xor a0, a0, a1 -; RV32-NEXT: ret -; -; RV64-LABEL: xorlow31: -; RV64: # %bb.0: -; RV64-NEXT: lui a1, 524288 -; RV64-NEXT: addiw a1, a1, -1 -; RV64-NEXT: xor a0, a0, a1 -; RV64-NEXT: ret +; CHECK-LABEL: xorlow31: +; CHECK: # %bb.0: +; CHECK-NEXT: lui a1, 524288 +; CHECK-NEXT: xnor a0, a0, a1 +; CHECK-NEXT: ret %xor = xor i32 %x, 2147483647 ret i32 %xor } @@ -164,8 +130,7 @@ define void @orarray100(ptr %a) { ; RV32: # %bb.0: # %entry ; RV32-NEXT: li a1, 0 ; RV32-NEXT: li a2, 0 -; RV32-NEXT: lui a3, 16 -; RV32-NEXT: addi a3, a3, -1 +; RV32-NEXT: lui a3, 1048560 ; RV32-NEXT: .LBB8_1: # %for.body ; RV32-NEXT: # =>This Inner Loop Header: Depth=1 ; RV32-NEXT: slli a4, a1, 2 @@ -175,7 +140,7 @@ define void @orarray100(ptr %a) { ; RV32-NEXT: seqz a6, a1 ; RV32-NEXT: add a2, a2, a6 ; RV32-NEXT: xori a6, a1, 100 -; RV32-NEXT: or a5, a5, a3 +; RV32-NEXT: orn a5, a5, a3 ; RV32-NEXT: or a6, a6, a2 ; RV32-NEXT: sw a5, 0(a4) ; RV32-NEXT: bnez a6, .LBB8_1 @@ -185,12 +150,11 @@ define void @orarray100(ptr %a) { ; RV64-LABEL: orarray100: ; RV64: # %bb.0: # %entry ; RV64-NEXT: addi a1, a0, 400 -; RV64-NEXT: lui a2, 16 -; RV64-NEXT: addi a2, a2, -1 +; RV64-NEXT: lui a2, 1048560 ; RV64-NEXT: .LBB8_1: # %for.body ; RV64-NEXT: # =>This Inner Loop Header: Depth=1 ; RV64-NEXT: lw a3, 0(a0) -; RV64-NEXT: or a3, a3, a2 +; RV64-NEXT: orn a3, a3, a2 ; RV64-NEXT: sw a3, 0(a0) ; RV64-NEXT: addi a0, a0, 4 ; RV64-NEXT: bne a0, a1, .LBB8_1 @@ -216,17 +180,16 @@ for.body: define void @orarray3(ptr %a) { ; CHECK-LABEL: orarray3: ; CHECK: # %bb.0: -; CHECK-NEXT: lui a1, 16 -; CHECK-NEXT: lw a2, 0(a0) -; CHECK-NEXT: lw a3, 4(a0) -; CHECK-NEXT: lw a4, 8(a0) -; CHECK-NEXT: addi a1, a1, -1 -; CHECK-NEXT: or a2, a2, a1 -; CHECK-NEXT: or a3, a3, a1 -; CHECK-NEXT: or a1, a4, a1 -; CHECK-NEXT: sw a2, 0(a0) -; CHECK-NEXT: sw a3, 4(a0) -; CHECK-NEXT: sw a1, 8(a0) +; CHECK-NEXT: lw a1, 0(a0) +; CHECK-NEXT: lw a2, 4(a0) +; CHECK-NEXT: lw a3, 8(a0) +; CHECK-NEXT: lui a4, 1048560 +; CHECK-NEXT: orn a1, a1, a4 +; CHECK-NEXT: orn a2, a2, a4 +; CHECK-NEXT: orn a3, a3, a4 +; CHECK-NEXT: sw a1, 0(a0) +; CHECK-NEXT: sw a2, 4(a0) +; CHECK-NEXT: sw a3, 8(a0) ; CHECK-NEXT: ret %1 = load i32, ptr %a, align 4 %or = or i32 %1, 65535 @@ -279,16 +242,14 @@ define i32 @compl(i32 %x) { define i32 @orlow12(i32 %x) { ; NOZBS32-LABEL: orlow12: ; NOZBS32: # %bb.0: -; NOZBS32-NEXT: lui a1, 1 -; NOZBS32-NEXT: addi a1, a1, -1 -; NOZBS32-NEXT: or a0, a0, a1 +; NOZBS32-NEXT: lui a1, 1048575 +; NOZBS32-NEXT: orn a0, a0, a1 ; NOZBS32-NEXT: ret ; ; NOZBS64-LABEL: orlow12: ; NOZBS64: # %bb.0: -; NOZBS64-NEXT: lui a1, 1 -; NOZBS64-NEXT: addiw a1, a1, -1 -; NOZBS64-NEXT: or a0, a0, a1 +; NOZBS64-NEXT: lui a1, 1048575 +; NOZBS64-NEXT: orn a0, a0, a1 ; NOZBS64-NEXT: ret ; ; ZBS-LABEL: orlow12: @@ -303,16 +264,14 @@ define i32 @orlow12(i32 %x) { define i32 @xorlow12(i32 %x) { ; NOZBS32-LABEL: xorlow12: ; NOZBS32: # %bb.0: -; NOZBS32-NEXT: lui a1, 1 -; NOZBS32-NEXT: addi a1, a1, -1 -; NOZBS32-NEXT: xor a0, a0, a1 +; NOZBS32-NEXT: lui a1, 1048575 +; NOZBS32-NEXT: xnor a0, a0, a1 ; NOZBS32-NEXT: ret ; ; NOZBS64-LABEL: xorlow12: ; NOZBS64: # %bb.0: -; NOZBS64-NEXT: lui a1, 1 -; NOZBS64-NEXT: addiw a1, a1, -1 -; NOZBS64-NEXT: xor a0, a0, a1 +; NOZBS64-NEXT: lui a1, 1048575 +; NOZBS64-NEXT: xnor a0, a0, a1 ; NOZBS64-NEXT: ret ; ; ZBS-LABEL: xorlow12: @@ -327,18 +286,16 @@ define i32 @xorlow12(i32 %x) { define i64 @andimm64(i64 %x) { ; RV32-LABEL: andimm64: ; RV32: # %bb.0: -; RV32-NEXT: lui a1, 1044496 -; RV32-NEXT: addi a1, a1, -1 -; RV32-NEXT: and a0, a0, a1 +; RV32-NEXT: lui a1, 4080 +; RV32-NEXT: andn a0, a0, a1 ; RV32-NEXT: li a1, 0 ; RV32-NEXT: ret ; ; RV64-LABEL: andimm64: ; RV64: # %bb.0: -; RV64-NEXT: lui a1, 65281 +; RV64-NEXT: lui a1, 983295 ; RV64-NEXT: slli a1, a1, 4 -; RV64-NEXT: addi a1, a1, -1 -; RV64-NEXT: and a0, a0, a1 +; RV64-NEXT: andn a0, a0, a1 ; RV64-NEXT: ret %and = and i64 %x, 4278255615 ret i64 %and @@ -347,19 +304,17 @@ define i64 @andimm64(i64 %x) { define i64 @andimm64srli(i64 %x) { ; RV32-LABEL: andimm64srli: ; RV32: # %bb.0: +; RV32-NEXT: lui a2, 1040384 +; RV32-NEXT: orn a0, a0, a2 ; RV32-NEXT: lui a2, 917504 ; RV32-NEXT: or a1, a1, a2 -; RV32-NEXT: lui a2, 8192 -; RV32-NEXT: addi a2, a2, -1 -; RV32-NEXT: or a0, a0, a2 ; RV32-NEXT: ret ; ; RV64-LABEL: andimm64srli: ; RV64: # %bb.0: ; RV64-NEXT: lui a1, 983040 ; RV64-NEXT: srli a1, a1, 3 -; RV64-NEXT: not a1, a1 -; RV64-NEXT: or a0, a0, a1 +; RV64-NEXT: orn a0, a0, a1 ; RV64-NEXT: ret %or = or i64 %x, -2305843009180139521 ret i64 %or