Index: llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h =================================================================== --- llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h +++ llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h @@ -59,6 +59,8 @@ bool selectAddiPair(SDValue N, SDValue &Val); + bool selectTwoBitsMask(SDValue N, SDValue &Val); + bool MatchSLLIUW(SDNode *N) const; bool selectVLOp(SDValue N, SDValue &VL); Index: llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -1287,6 +1287,23 @@ return false; } +// Check if (or r, imm) can be optimized to (bseti (bseti r, imm0), imm1). +bool RISCVDAGToDAGISel::selectTwoBitsMask(SDValue N, SDValue &Val) { + if (auto *ConstOp = dyn_cast(N)) { + if (!(ConstOp->hasOneUse())) + return false; + // The immediate should not be a simm12. + if (isInt<12>(ConstOp->getSExtValue())) + return false; + // The immediate must have exactly two bits set. + if (countPopulation(ConstOp->getZExtValue()) == 2) { + Val = N; + return true; + } + } + return false; +} + // Check if (add r, imm) can be optimized to (ADDI (ADDI r, imm0), imm1), // in which imm = imm0 + imm1 and both imm0 and imm1 are simm12. bool RISCVDAGToDAGISel::selectAddiPair(SDValue N, SDValue &Val) { Index: llvm/lib/Target/RISCV/RISCVInstrInfoB.td =================================================================== --- llvm/lib/Target/RISCV/RISCVInstrInfoB.td +++ llvm/lib/Target/RISCV/RISCVInstrInfoB.td @@ -87,6 +87,21 @@ return !isInt<12>(Imm) && isPowerOf2_32(Imm); }], BSETINVXForm>; +// Check if this mask has two set bits and is used only once. +def BSETINVTwoBitsMask : ComplexPattern; + +def BSETINVTwoBtisMaskLow : SDNodeXFormgetZExtValue(); + return CurDAG->getTargetConstant(countTrailingZeros(I), SDLoc(N), + N->getValueType(0)); +}]>; + +def BSETINVTwoBtisMaskHigh : SDNodeXFormgetZExtValue(); + return CurDAG->getTargetConstant(63 - countLeadingZeros(I), SDLoc(N), + N->getValueType(0)); +}]>; + //===----------------------------------------------------------------------===// // Instruction class templates //===----------------------------------------------------------------------===// @@ -723,6 +738,13 @@ def : Pat<(and (srl GPR:$rs1, uimmlog2xlen:$shamt), (XLenVT 1)), (BEXTI GPR:$rs1, uimmlog2xlen:$shamt)>; + +def : Pat<(or GPR:$rs1, (BSETINVTwoBitsMask GPR:$rs2)), + (BSETI (BSETI GPR:$rs1, (BSETINVTwoBtisMaskLow GPR:$rs2)), + (BSETINVTwoBtisMaskHigh GPR:$rs2))>; +def : Pat<(xor GPR:$rs1, (BSETINVTwoBitsMask GPR:$rs2)), + (BINVI (BINVI GPR:$rs1, (BSETINVTwoBtisMaskLow GPR:$rs2)), + (BSETINVTwoBtisMaskHigh GPR:$rs2))>; } // There's no encoding for roli in the the 'B' extension as it can be Index: llvm/test/CodeGen/RISCV/rv32zbs.ll =================================================================== --- llvm/test/CodeGen/RISCV/rv32zbs.ll +++ llvm/test/CodeGen/RISCV/rv32zbs.ll @@ -720,16 +720,14 @@ ; ; RV32IB-LABEL: xor_i32_4098: ; RV32IB: # %bb.0: -; RV32IB-NEXT: lui a1, 1 -; RV32IB-NEXT: addi a1, a1, 2 -; RV32IB-NEXT: xor a0, a0, a1 +; RV32IB-NEXT: binvi a0, a0, 1 +; RV32IB-NEXT: binvi a0, a0, 12 ; RV32IB-NEXT: ret ; ; RV32IBS-LABEL: xor_i32_4098: ; RV32IBS: # %bb.0: -; RV32IBS-NEXT: lui a1, 1 -; RV32IBS-NEXT: addi a1, a1, 2 -; RV32IBS-NEXT: xor a0, a0, a1 +; RV32IBS-NEXT: binvi a0, a0, 1 +; RV32IBS-NEXT: binvi a0, a0, 12 ; RV32IBS-NEXT: ret %xor = xor i32 %a, 4098 ret i32 %xor @@ -789,16 +787,14 @@ ; ; RV32IB-LABEL: or_i32_4098: ; RV32IB: # %bb.0: -; RV32IB-NEXT: lui a1, 1 -; RV32IB-NEXT: addi a1, a1, 2 -; RV32IB-NEXT: or a0, a0, a1 +; RV32IB-NEXT: bseti a0, a0, 1 +; RV32IB-NEXT: bseti a0, a0, 12 ; RV32IB-NEXT: ret ; ; RV32IBS-LABEL: or_i32_4098: ; RV32IBS: # %bb.0: -; RV32IBS-NEXT: lui a1, 1 -; RV32IBS-NEXT: addi a1, a1, 2 -; RV32IBS-NEXT: or a0, a0, a1 +; RV32IBS-NEXT: bseti a0, a0, 1 +; RV32IBS-NEXT: bseti a0, a0, 12 ; RV32IBS-NEXT: ret %or = or i32 %a, 4098 ret i32 %or Index: llvm/test/CodeGen/RISCV/rv64zbs.ll =================================================================== --- llvm/test/CodeGen/RISCV/rv64zbs.ll +++ llvm/test/CodeGen/RISCV/rv64zbs.ll @@ -1221,18 +1221,14 @@ ; ; RV64IB-LABEL: xor_i64_large: ; RV64IB: # %bb.0: -; RV64IB-NEXT: addi a1, zero, 1 -; RV64IB-NEXT: slli a1, a1, 32 -; RV64IB-NEXT: addi a1, a1, 1 -; RV64IB-NEXT: xor a0, a0, a1 +; RV64IB-NEXT: binvi a0, a0, 0 +; RV64IB-NEXT: binvi a0, a0, 32 ; RV64IB-NEXT: ret ; ; RV64IBS-LABEL: xor_i64_large: ; RV64IBS: # %bb.0: -; RV64IBS-NEXT: addi a1, zero, 1 -; RV64IBS-NEXT: slli a1, a1, 32 -; RV64IBS-NEXT: addi a1, a1, 1 -; RV64IBS-NEXT: xor a0, a0, a1 +; RV64IBS-NEXT: binvi a0, a0, 0 +; RV64IBS-NEXT: binvi a0, a0, 32 ; RV64IBS-NEXT: ret %xor = xor i64 %a, 4294967297 ret i64 %xor @@ -1293,18 +1289,14 @@ ; ; RV64IB-LABEL: or_i64_large: ; RV64IB: # %bb.0: -; RV64IB-NEXT: addi a1, zero, 1 -; RV64IB-NEXT: slli a1, a1, 32 -; RV64IB-NEXT: addi a1, a1, 1 -; RV64IB-NEXT: or a0, a0, a1 +; RV64IB-NEXT: bseti a0, a0, 0 +; RV64IB-NEXT: bseti a0, a0, 32 ; RV64IB-NEXT: ret ; ; RV64IBS-LABEL: or_i64_large: ; RV64IBS: # %bb.0: -; RV64IBS-NEXT: addi a1, zero, 1 -; RV64IBS-NEXT: slli a1, a1, 32 -; RV64IBS-NEXT: addi a1, a1, 1 -; RV64IBS-NEXT: or a0, a0, a1 +; RV64IBS-NEXT: bseti a0, a0, 0 +; RV64IBS-NEXT: bseti a0, a0, 32 ; RV64IBS-NEXT: ret %or = or i64 %a, 4294967297 ret i64 %or