Index: llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -528,6 +528,60 @@ break; } + + // Optimize (add (shl x, c0), (shl y, c1)) -> + // (SLLI (SH*ADD y, x), c0), if c1-c0 equals to [1|2|3]. + case ISD::ADD: { + // Perform this optimization only in the zba extension. + if (!Subtarget->hasStdExtZba()) + break; + + // Skip for vector types. + if (VT.isVector()) + break; + + // The two operand nodes must be SHL and have no other use. + SDValue N0 = Node->getOperand(0); + SDValue N1 = Node->getOperand(1); + if (N0.getOpcode() != ISD::SHL || N1.getOpcode() != ISD::SHL || + !N0.hasOneUse() || !N1.hasOneUse()) + break; + + // Check c0 and c1. + auto *NC0 = dyn_cast(N0->getOperand(1)); + auto *NC1 = dyn_cast(N1->getOperand(1)); + if (!NC0 || !NC1) + break; + int64_t C0 = NC0->getSExtValue(); + int64_t C1 = NC1->getSExtValue(); + if (C0 <= 0 || C1 <= 0 || C0 >= Subtarget->getXLen() || + C1 >= Subtarget->getXLen()) + break; + int64_t Bits = std::min(C0, C1); + int64_t Diff = std::max(C0, C1) - Bits; + + // Select SH1ADD/SH2ADD/SH3ADD or skip. + unsigned Opc; + if (Diff == 1) + Opc = RISCV::SH1ADD; + else if (Diff == 2) + Opc = RISCV::SH2ADD; + else if (Diff == 3) + Opc = RISCV::SH3ADD; + else + break; + + // Build machine nodes and replace SDNodes. + SDValue NS = (C0 < C1) ? N0->getOperand(0) : N1->getOperand(0); + SDValue NL = (C0 > C1) ? N0->getOperand(0) : N1->getOperand(0); + SDNode *NAD = CurDAG->getMachineNode(Opc, DL, VT, NL, NS); + SDNode *NSH = + CurDAG->getMachineNode(RISCV::SLLI, DL, VT, SDValue(NAD, 0), + CurDAG->getTargetConstant(Bits, DL, VT)); + ReplaceNode(Node, NSH); + return; + } + case ISD::AND: { auto *N1C = dyn_cast(Node->getOperand(1)); if (!N1C) Index: llvm/test/CodeGen/RISCV/rv32zba.ll =================================================================== --- llvm/test/CodeGen/RISCV/rv32zba.ll +++ llvm/test/CodeGen/RISCV/rv32zba.ll @@ -796,16 +796,14 @@ ; ; RV32B-LABEL: addshl_5_6: ; RV32B: # %bb.0: +; RV32B-NEXT: sh1add a0, a1, a0 ; RV32B-NEXT: slli a0, a0, 5 -; RV32B-NEXT: slli a1, a1, 6 -; RV32B-NEXT: add a0, a0, a1 ; RV32B-NEXT: ret ; ; RV32ZBA-LABEL: addshl_5_6: ; RV32ZBA: # %bb.0: +; RV32ZBA-NEXT: sh1add a0, a1, a0 ; RV32ZBA-NEXT: slli a0, a0, 5 -; RV32ZBA-NEXT: slli a1, a1, 6 -; RV32ZBA-NEXT: add a0, a0, a1 ; RV32ZBA-NEXT: ret %c = shl i32 %a, 5 %d = shl i32 %b, 6 @@ -823,16 +821,14 @@ ; ; RV32B-LABEL: addshl_5_7: ; RV32B: # %bb.0: +; RV32B-NEXT: sh2add a0, a1, a0 ; RV32B-NEXT: slli a0, a0, 5 -; RV32B-NEXT: slli a1, a1, 7 -; RV32B-NEXT: add a0, a0, a1 ; RV32B-NEXT: ret ; ; RV32ZBA-LABEL: addshl_5_7: ; RV32ZBA: # %bb.0: +; RV32ZBA-NEXT: sh2add a0, a1, a0 ; RV32ZBA-NEXT: slli a0, a0, 5 -; RV32ZBA-NEXT: slli a1, a1, 7 -; RV32ZBA-NEXT: add a0, a0, a1 ; RV32ZBA-NEXT: ret %c = shl i32 %a, 5 %d = shl i32 %b, 7 @@ -850,16 +846,14 @@ ; ; RV32B-LABEL: addshl_5_8: ; RV32B: # %bb.0: +; RV32B-NEXT: sh3add a0, a1, a0 ; RV32B-NEXT: slli a0, a0, 5 -; RV32B-NEXT: slli a1, a1, 8 -; RV32B-NEXT: add a0, a0, a1 ; RV32B-NEXT: ret ; ; RV32ZBA-LABEL: addshl_5_8: ; RV32ZBA: # %bb.0: +; RV32ZBA-NEXT: sh3add a0, a1, a0 ; RV32ZBA-NEXT: slli a0, a0, 5 -; RV32ZBA-NEXT: slli a1, a1, 8 -; RV32ZBA-NEXT: add a0, a0, a1 ; RV32ZBA-NEXT: ret %c = shl i32 %a, 5 %d = shl i32 %b, 8 Index: llvm/test/CodeGen/RISCV/rv64zba.ll =================================================================== --- llvm/test/CodeGen/RISCV/rv64zba.ll +++ llvm/test/CodeGen/RISCV/rv64zba.ll @@ -1407,16 +1407,14 @@ ; ; RV64B-LABEL: addshl32_5_6: ; RV64B: # %bb.0: +; RV64B-NEXT: sh1add a0, a1, a0 ; RV64B-NEXT: slliw a0, a0, 5 -; RV64B-NEXT: slliw a1, a1, 6 -; RV64B-NEXT: addw a0, a0, a1 ; RV64B-NEXT: ret ; ; RV64ZBA-LABEL: addshl32_5_6: ; RV64ZBA: # %bb.0: +; RV64ZBA-NEXT: sh1add a0, a1, a0 ; RV64ZBA-NEXT: slliw a0, a0, 5 -; RV64ZBA-NEXT: slliw a1, a1, 6 -; RV64ZBA-NEXT: addw a0, a0, a1 ; RV64ZBA-NEXT: ret %c = shl i32 %a, 5 %d = shl i32 %b, 6 @@ -1434,16 +1432,14 @@ ; ; RV64B-LABEL: addshl64_5_6: ; RV64B: # %bb.0: +; RV64B-NEXT: sh1add a0, a1, a0 ; RV64B-NEXT: slli a0, a0, 5 -; RV64B-NEXT: slli a1, a1, 6 -; RV64B-NEXT: add a0, a0, a1 ; RV64B-NEXT: ret ; ; RV64ZBA-LABEL: addshl64_5_6: ; RV64ZBA: # %bb.0: +; RV64ZBA-NEXT: sh1add a0, a1, a0 ; RV64ZBA-NEXT: slli a0, a0, 5 -; RV64ZBA-NEXT: slli a1, a1, 6 -; RV64ZBA-NEXT: add a0, a0, a1 ; RV64ZBA-NEXT: ret %c = shl i64 %a, 5 %d = shl i64 %b, 6 @@ -1461,16 +1457,14 @@ ; ; RV64B-LABEL: addshl32_5_7: ; RV64B: # %bb.0: +; RV64B-NEXT: sh2add a0, a1, a0 ; RV64B-NEXT: slliw a0, a0, 5 -; RV64B-NEXT: slliw a1, a1, 7 -; RV64B-NEXT: addw a0, a0, a1 ; RV64B-NEXT: ret ; ; RV64ZBA-LABEL: addshl32_5_7: ; RV64ZBA: # %bb.0: +; RV64ZBA-NEXT: sh2add a0, a1, a0 ; RV64ZBA-NEXT: slliw a0, a0, 5 -; RV64ZBA-NEXT: slliw a1, a1, 7 -; RV64ZBA-NEXT: addw a0, a0, a1 ; RV64ZBA-NEXT: ret %c = shl i32 %a, 5 %d = shl i32 %b, 7 @@ -1488,16 +1482,14 @@ ; ; RV64B-LABEL: addshl64_5_7: ; RV64B: # %bb.0: +; RV64B-NEXT: sh2add a0, a1, a0 ; RV64B-NEXT: slli a0, a0, 5 -; RV64B-NEXT: slli a1, a1, 7 -; RV64B-NEXT: add a0, a0, a1 ; RV64B-NEXT: ret ; ; RV64ZBA-LABEL: addshl64_5_7: ; RV64ZBA: # %bb.0: +; RV64ZBA-NEXT: sh2add a0, a1, a0 ; RV64ZBA-NEXT: slli a0, a0, 5 -; RV64ZBA-NEXT: slli a1, a1, 7 -; RV64ZBA-NEXT: add a0, a0, a1 ; RV64ZBA-NEXT: ret %c = shl i64 %a, 5 %d = shl i64 %b, 7 @@ -1515,16 +1507,14 @@ ; ; RV64B-LABEL: addshl32_5_8: ; RV64B: # %bb.0: +; RV64B-NEXT: sh3add a0, a1, a0 ; RV64B-NEXT: slliw a0, a0, 5 -; RV64B-NEXT: slliw a1, a1, 8 -; RV64B-NEXT: addw a0, a0, a1 ; RV64B-NEXT: ret ; ; RV64ZBA-LABEL: addshl32_5_8: ; RV64ZBA: # %bb.0: +; RV64ZBA-NEXT: sh3add a0, a1, a0 ; RV64ZBA-NEXT: slliw a0, a0, 5 -; RV64ZBA-NEXT: slliw a1, a1, 8 -; RV64ZBA-NEXT: addw a0, a0, a1 ; RV64ZBA-NEXT: ret %c = shl i32 %a, 5 %d = shl i32 %b, 8 @@ -1542,16 +1532,14 @@ ; ; RV64B-LABEL: addshl64_5_8: ; RV64B: # %bb.0: +; RV64B-NEXT: sh3add a0, a1, a0 ; RV64B-NEXT: slli a0, a0, 5 -; RV64B-NEXT: slli a1, a1, 8 -; RV64B-NEXT: add a0, a0, a1 ; RV64B-NEXT: ret ; ; RV64ZBA-LABEL: addshl64_5_8: ; RV64ZBA: # %bb.0: +; RV64ZBA-NEXT: sh3add a0, a1, a0 ; RV64ZBA-NEXT: slli a0, a0, 5 -; RV64ZBA-NEXT: slli a1, a1, 8 -; RV64ZBA-NEXT: add a0, a0, a1 ; RV64ZBA-NEXT: ret %c = shl i64 %a, 5 %d = shl i64 %b, 8