Index: llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h =================================================================== --- llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h +++ llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h @@ -58,6 +58,7 @@ bool selectZExti32(SDValue N, SDValue &Val); bool MatchSLLIUW(SDNode *N) const; + bool MatchBSETINVORImm(ConstantSDNode *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,18 @@ return false; } +// Check whether or/xor with immediate can be optimized with BSETI/BINVI +// in the zbs extension, if the immediate operand matches specific pattern. +bool RISCVDAGToDAGISel::MatchBSETINVORImm(ConstantSDNode *N) const { + if (!N->hasOneUse()) + return false; + // The imm should not be a simm12. + if (isInt<12>(N->getSExtValue())) + return false; + // There should be only one set bit from bit 12 to the top. + return isPowerOf2_64(N->getZExtValue() & ~0xfff); +} + // Check that it is a SLLIUW (Shift Logical Left Immediate Unsigned i32 // on RV64). // SLLIUW is the same as SLLI except for the fact that it clears the bits Index: llvm/lib/Target/RISCV/RISCVInstrInfoB.td =================================================================== --- llvm/lib/Target/RISCV/RISCVInstrInfoB.td +++ llvm/lib/Target/RISCV/RISCVInstrInfoB.td @@ -90,13 +90,13 @@ // Check if (or r, i) can be optimized to (BSETI (BSETI r, i0), i1), // in which i = (1 << i0) | (1 << i1). def BSETINVTwoBitsMask : PatLeaf<(imm), [{ - if (!N->hasOneUse()) - return false; - // The immediate should not be a simm12. - if (isInt<12>(N->getSExtValue())) - return false; - // The immediate must have exactly two bits set. - return countPopulation(N->getZExtValue()) == 2; + if (!N->hasOneUse()) + return false; + // The immediate should not be a simm12. + if (isInt<12>(N->getSExtValue())) + return false; + // The immediate must have exactly two bits set. + return countPopulation(N->getZExtValue()) == 2; }]>; def BSETINVTwoBitsMaskLow : SDNodeXFormgetValueType(0)); }]>; +// Check if (or r, imm) can be optimized to (BSETI (ORI r, i0), i1), +// in which imm = i0 | (1 << i1). +def BSETINVORIMaskP : PatLeaf<(imm), [{ + if (!MatchBSETINVORImm(N)) + return false; + // Bit 11 of imm must be clear. + return !(N->getZExtValue() & (1 << 11)); +}]>; + +// Check if (or r, imm) can be optimized to (BSETI (BSETI (ORI r, i0), 11), i1) +// in which imm = i0 | (1 << 11) | (1 << i1). +def BSETINVORIMaskN : PatLeaf<(imm), [{ + if (!MatchBSETINVORImm(N)) + return false; + // Bit 11 of imm must be set. + return N->getZExtValue() & (1 << 11); +}]>; + +def BSETINVORIMaskLow : SDNodeXFormgetTargetConstant(N->getZExtValue() & 0x7ff, + SDLoc(N), N->getValueType(0)); +}]>; + //===----------------------------------------------------------------------===// // Instruction class templates //===----------------------------------------------------------------------===// @@ -754,6 +777,20 @@ def : Pat<(xor GPR:$r, BSETINVTwoBitsMask:$i), (BINVI (BINVI GPR:$r, (BSETINVTwoBitsMaskLow BSETINVTwoBitsMask:$i)), (BSETINVTwoBitsMaskHigh BSETINVTwoBitsMask:$i))>; +def : Pat<(or GPR:$r, BSETINVORIMaskP:$i), + (BSETI (ORI GPR:$r, (BSETINVORIMaskLow BSETINVORIMaskP:$i)), + (BSETINVTwoBitsMaskHigh BSETINVORIMaskP:$i))>; +def : Pat<(xor GPR:$r, BSETINVORIMaskP:$i), + (BINVI (XORI GPR:$r, (BSETINVORIMaskLow BSETINVORIMaskP:$i)), + (BSETINVTwoBitsMaskHigh BSETINVORIMaskP:$i))>; +def : Pat<(or GPR:$r, BSETINVORIMaskN:$i), + (BSETI (BSETI (ORI GPR:$r, (BSETINVORIMaskLow BSETINVORIMaskN:$i)), + 11), + (BSETINVTwoBitsMaskHigh BSETINVORIMaskN:$i))>; +def : Pat<(xor GPR:$r, BSETINVORIMaskN:$i), + (BINVI (BINVI (XORI GPR:$r, (BSETINVORIMaskLow BSETINVORIMaskN:$i)), + 11), + (BSETINVTwoBitsMaskHigh BSETINVORIMaskN:$i))>; } // 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 @@ -743,16 +743,14 @@ ; ; RV32IB-LABEL: xor_i32_4099: ; RV32IB: # %bb.0: -; RV32IB-NEXT: lui a1, 1 -; RV32IB-NEXT: addi a1, a1, 3 -; RV32IB-NEXT: xor a0, a0, a1 +; RV32IB-NEXT: xori a0, a0, 3 +; RV32IB-NEXT: binvi a0, a0, 12 ; RV32IB-NEXT: ret ; ; RV32IBS-LABEL: xor_i32_4099: ; RV32IBS: # %bb.0: -; RV32IBS-NEXT: lui a1, 1 -; RV32IBS-NEXT: addi a1, a1, 3 -; RV32IBS-NEXT: xor a0, a0, a1 +; RV32IBS-NEXT: xori a0, a0, 3 +; RV32IBS-NEXT: binvi a0, a0, 12 ; RV32IBS-NEXT: ret %xor = xor i32 %a, 4099 ret i32 %xor @@ -787,16 +785,14 @@ ; ; RV32IB-LABEL: xor_i32_66901: ; RV32IB: # %bb.0: -; RV32IB-NEXT: lui a1, 16 -; RV32IB-NEXT: addi a1, a1, 1365 -; RV32IB-NEXT: xor a0, a0, a1 +; RV32IB-NEXT: xori a0, a0, 1365 +; RV32IB-NEXT: binvi a0, a0, 16 ; RV32IB-NEXT: ret ; ; RV32IBS-LABEL: xor_i32_66901: ; RV32IBS: # %bb.0: -; RV32IBS-NEXT: lui a1, 16 -; RV32IBS-NEXT: addi a1, a1, 1365 -; RV32IBS-NEXT: xor a0, a0, a1 +; RV32IBS-NEXT: xori a0, a0, 1365 +; RV32IBS-NEXT: binvi a0, a0, 16 ; RV32IBS-NEXT: ret %xor = xor i32 %a, 66901 ret i32 %xor @@ -812,16 +808,16 @@ ; ; RV32IB-LABEL: xor_i32_6147: ; RV32IB: # %bb.0: -; RV32IB-NEXT: lui a1, 2 -; RV32IB-NEXT: addi a1, a1, -2045 -; RV32IB-NEXT: xor a0, a0, a1 +; RV32IB-NEXT: xori a0, a0, 3 +; RV32IB-NEXT: binvi a0, a0, 11 +; RV32IB-NEXT: binvi a0, a0, 12 ; RV32IB-NEXT: ret ; ; RV32IBS-LABEL: xor_i32_6147: ; RV32IBS: # %bb.0: -; RV32IBS-NEXT: lui a1, 2 -; RV32IBS-NEXT: addi a1, a1, -2045 -; RV32IBS-NEXT: xor a0, a0, a1 +; RV32IBS-NEXT: xori a0, a0, 3 +; RV32IBS-NEXT: binvi a0, a0, 11 +; RV32IBS-NEXT: binvi a0, a0, 12 ; RV32IBS-NEXT: ret %xor = xor i32 %a, 6147 ret i32 %xor @@ -860,16 +856,14 @@ ; ; RV32IB-LABEL: or_i32_4099: ; RV32IB: # %bb.0: -; RV32IB-NEXT: lui a1, 1 -; RV32IB-NEXT: addi a1, a1, 3 -; RV32IB-NEXT: or a0, a0, a1 +; RV32IB-NEXT: ori a0, a0, 3 +; RV32IB-NEXT: bseti a0, a0, 12 ; RV32IB-NEXT: ret ; ; RV32IBS-LABEL: or_i32_4099: ; RV32IBS: # %bb.0: -; RV32IBS-NEXT: lui a1, 1 -; RV32IBS-NEXT: addi a1, a1, 3 -; RV32IBS-NEXT: or a0, a0, a1 +; RV32IBS-NEXT: ori a0, a0, 3 +; RV32IBS-NEXT: bseti a0, a0, 12 ; RV32IBS-NEXT: ret %or = or i32 %a, 4099 ret i32 %or @@ -904,16 +898,14 @@ ; ; RV32IB-LABEL: or_i32_66901: ; RV32IB: # %bb.0: -; RV32IB-NEXT: lui a1, 16 -; RV32IB-NEXT: addi a1, a1, 1365 -; RV32IB-NEXT: or a0, a0, a1 +; RV32IB-NEXT: ori a0, a0, 1365 +; RV32IB-NEXT: bseti a0, a0, 16 ; RV32IB-NEXT: ret ; ; RV32IBS-LABEL: or_i32_66901: ; RV32IBS: # %bb.0: -; RV32IBS-NEXT: lui a1, 16 -; RV32IBS-NEXT: addi a1, a1, 1365 -; RV32IBS-NEXT: or a0, a0, a1 +; RV32IBS-NEXT: ori a0, a0, 1365 +; RV32IBS-NEXT: bseti a0, a0, 16 ; RV32IBS-NEXT: ret %or = or i32 %a, 66901 ret i32 %or @@ -929,16 +921,16 @@ ; ; RV32IB-LABEL: or_i32_6147: ; RV32IB: # %bb.0: -; RV32IB-NEXT: lui a1, 2 -; RV32IB-NEXT: addi a1, a1, -2045 -; RV32IB-NEXT: or a0, a0, a1 +; RV32IB-NEXT: ori a0, a0, 3 +; RV32IB-NEXT: bseti a0, a0, 11 +; RV32IB-NEXT: bseti a0, a0, 12 ; RV32IB-NEXT: ret ; ; RV32IBS-LABEL: or_i32_6147: ; RV32IBS: # %bb.0: -; RV32IBS-NEXT: lui a1, 2 -; RV32IBS-NEXT: addi a1, a1, -2045 -; RV32IBS-NEXT: or a0, a0, a1 +; RV32IBS-NEXT: ori a0, a0, 3 +; RV32IBS-NEXT: bseti a0, a0, 11 +; RV32IBS-NEXT: bseti a0, a0, 12 ; RV32IBS-NEXT: ret %or = or i32 %a, 6147 ret i32 %or Index: llvm/test/CodeGen/RISCV/rv64zbs.ll =================================================================== --- llvm/test/CodeGen/RISCV/rv64zbs.ll +++ llvm/test/CodeGen/RISCV/rv64zbs.ll @@ -1244,16 +1244,14 @@ ; ; RV64IB-LABEL: xor_i64_4099: ; RV64IB: # %bb.0: -; RV64IB-NEXT: lui a1, 1 -; RV64IB-NEXT: addiw a1, a1, 3 -; RV64IB-NEXT: xor a0, a0, a1 +; RV64IB-NEXT: xori a0, a0, 3 +; RV64IB-NEXT: binvi a0, a0, 12 ; RV64IB-NEXT: ret ; ; RV64IBS-LABEL: xor_i64_4099: ; RV64IBS: # %bb.0: -; RV64IBS-NEXT: lui a1, 1 -; RV64IBS-NEXT: addiw a1, a1, 3 -; RV64IBS-NEXT: xor a0, a0, a1 +; RV64IBS-NEXT: xori a0, a0, 3 +; RV64IBS-NEXT: binvi a0, a0, 12 ; RV64IBS-NEXT: ret %xor = xor i64 %a, 4099 ret i64 %xor @@ -1312,16 +1310,14 @@ ; ; RV64IB-LABEL: xor_i64_66901: ; RV64IB: # %bb.0: -; RV64IB-NEXT: lui a1, 16 -; RV64IB-NEXT: addiw a1, a1, 1365 -; RV64IB-NEXT: xor a0, a0, a1 +; RV64IB-NEXT: xori a0, a0, 1365 +; RV64IB-NEXT: binvi a0, a0, 16 ; RV64IB-NEXT: ret ; ; RV64IBS-LABEL: xor_i64_66901: ; RV64IBS: # %bb.0: -; RV64IBS-NEXT: lui a1, 16 -; RV64IBS-NEXT: addiw a1, a1, 1365 -; RV64IBS-NEXT: xor a0, a0, a1 +; RV64IBS-NEXT: xori a0, a0, 1365 +; RV64IBS-NEXT: binvi a0, a0, 16 ; RV64IBS-NEXT: ret %xor = xor i64 %a, 66901 ret i64 %xor @@ -1337,16 +1333,16 @@ ; ; RV64IB-LABEL: xor_i64_6147: ; RV64IB: # %bb.0: -; RV64IB-NEXT: lui a1, 2 -; RV64IB-NEXT: addiw a1, a1, -2045 -; RV64IB-NEXT: xor a0, a0, a1 +; RV64IB-NEXT: xori a0, a0, 3 +; RV64IB-NEXT: binvi a0, a0, 11 +; RV64IB-NEXT: binvi a0, a0, 12 ; RV64IB-NEXT: ret ; ; RV64IBS-LABEL: xor_i64_6147: ; RV64IBS: # %bb.0: -; RV64IBS-NEXT: lui a1, 2 -; RV64IBS-NEXT: addiw a1, a1, -2045 -; RV64IBS-NEXT: xor a0, a0, a1 +; RV64IBS-NEXT: xori a0, a0, 3 +; RV64IBS-NEXT: binvi a0, a0, 11 +; RV64IBS-NEXT: binvi a0, a0, 12 ; RV64IBS-NEXT: ret %xor = xor i64 %a, 6147 ret i64 %xor @@ -1362,16 +1358,14 @@ ; ; RV64IB-LABEL: or_i64_4099: ; RV64IB: # %bb.0: -; RV64IB-NEXT: lui a1, 1 -; RV64IB-NEXT: addiw a1, a1, 3 -; RV64IB-NEXT: or a0, a0, a1 +; RV64IB-NEXT: ori a0, a0, 3 +; RV64IB-NEXT: bseti a0, a0, 12 ; RV64IB-NEXT: ret ; ; RV64IBS-LABEL: or_i64_4099: ; RV64IBS: # %bb.0: -; RV64IBS-NEXT: lui a1, 1 -; RV64IBS-NEXT: addiw a1, a1, 3 -; RV64IBS-NEXT: or a0, a0, a1 +; RV64IBS-NEXT: ori a0, a0, 3 +; RV64IBS-NEXT: bseti a0, a0, 12 ; RV64IBS-NEXT: ret %or = or i64 %a, 4099 ret i64 %or @@ -1406,16 +1400,14 @@ ; ; RV64IB-LABEL: or_i64_66901: ; RV64IB: # %bb.0: -; RV64IB-NEXT: lui a1, 16 -; RV64IB-NEXT: addiw a1, a1, 1365 -; RV64IB-NEXT: or a0, a0, a1 +; RV64IB-NEXT: ori a0, a0, 1365 +; RV64IB-NEXT: bseti a0, a0, 16 ; RV64IB-NEXT: ret ; ; RV64IBS-LABEL: or_i64_66901: ; RV64IBS: # %bb.0: -; RV64IBS-NEXT: lui a1, 16 -; RV64IBS-NEXT: addiw a1, a1, 1365 -; RV64IBS-NEXT: or a0, a0, a1 +; RV64IBS-NEXT: ori a0, a0, 1365 +; RV64IBS-NEXT: bseti a0, a0, 16 ; RV64IBS-NEXT: ret %or = or i64 %a, 66901 ret i64 %or @@ -1431,16 +1423,16 @@ ; ; RV64IB-LABEL: or_i64_6147: ; RV64IB: # %bb.0: -; RV64IB-NEXT: lui a1, 2 -; RV64IB-NEXT: addiw a1, a1, -2045 -; RV64IB-NEXT: or a0, a0, a1 +; RV64IB-NEXT: ori a0, a0, 3 +; RV64IB-NEXT: bseti a0, a0, 11 +; RV64IB-NEXT: bseti a0, a0, 12 ; RV64IB-NEXT: ret ; ; RV64IBS-LABEL: or_i64_6147: ; RV64IBS: # %bb.0: -; RV64IBS-NEXT: lui a1, 2 -; RV64IBS-NEXT: addiw a1, a1, -2045 -; RV64IBS-NEXT: or a0, a0, a1 +; RV64IBS-NEXT: ori a0, a0, 3 +; RV64IBS-NEXT: bseti a0, a0, 11 +; RV64IBS-NEXT: bseti a0, a0, 12 ; RV64IBS-NEXT: ret %xor = or i64 %a, 6147 ret i64 %xor