diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h @@ -57,6 +57,8 @@ bool selectSExti32(SDValue N, SDValue &Val); bool selectZExti32(SDValue N, SDValue &Val); + bool selectAddiPair(SDValue N, SDValue &Val); + bool MatchSLLIUW(SDNode *N) const; bool selectVLOp(SDValue N, SDValue &VL); diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -379,28 +379,6 @@ MVT VT = Node->getSimpleValueType(0); switch (Opcode) { - case ISD::ADD: { - // Optimize (add r, imm) to (addi (addi r, imm0) imm1) if applicable. The - // immediate must be in specific ranges and have a single use. - if (auto *ConstOp = dyn_cast(Node->getOperand(1))) { - if (!(ConstOp->hasOneUse())) - break; - // The imm must be in range [-4096,-2049] or [2048,4094]. - int64_t Imm = ConstOp->getSExtValue(); - if (!(-4096 <= Imm && Imm <= -2049) && !(2048 <= Imm && Imm <= 4094)) - break; - // Break the imm to imm0+imm1. - const SDValue ImmOp0 = CurDAG->getTargetConstant(Imm - Imm / 2, DL, VT); - const SDValue ImmOp1 = CurDAG->getTargetConstant(Imm / 2, DL, VT); - auto *NodeAddi0 = CurDAG->getMachineNode(RISCV::ADDI, DL, VT, - Node->getOperand(0), ImmOp0); - auto *NodeAddi1 = CurDAG->getMachineNode(RISCV::ADDI, DL, VT, - SDValue(NodeAddi0, 0), ImmOp1); - ReplaceNode(Node, NodeAddi1); - return; - } - break; - } case ISD::Constant: { auto *ConstNode = cast(Node); if (VT == XLenVT && ConstNode->isNullValue()) { @@ -1092,6 +1070,23 @@ 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) { + if (auto *ConstOp = dyn_cast(N)) { + // The immediate operand must have only use. + if (!(ConstOp->hasOneUse())) + return false; + // The immediate operand must be in range [-4096,-2049] or [2048,4094]. + int64_t Imm = ConstOp->getSExtValue(); + if ((-4096 <= Imm && Imm <= -2049) || (2048 <= Imm && Imm <= 4094)) { + Val = N; + return true; + } + } + return false; +} + // 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 diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -145,7 +145,7 @@ if (!MCOp.evaluateAsConstantImm(Imm)) return false; if (STI.getTargetTriple().isArch64Bit()) - return isUInt<6>(Imm); + return isUInt<6>(Imm); return isUInt<5>(Imm); }]; let OperandType = "OPERAND_UIMMLOG2XLEN"; @@ -343,6 +343,22 @@ N->getValueType(0)); }]>; +// Check if an addition can be broken to a pair of ADDI. +def AddiPair : ComplexPattern; + +// Return imm/2. +def AddiPairImmA : SDNodeXFormgetTargetConstant(N->getSExtValue() / 2, SDLoc(N), + N->getValueType(0)); +}]>; + +// Return imm - imm/2. +def AddiPairImmB : SDNodeXFormgetSExtValue(); + return CurDAG->getTargetConstant(Imm - Imm / 2, SDLoc(N), + N->getValueType(0)); +}]>; + //===----------------------------------------------------------------------===// // Instruction Formats //===----------------------------------------------------------------------===// @@ -1274,6 +1290,11 @@ // debugger if possible. def : Pat<(debugtrap), (EBREAK)>; +/// Simple optimization +def : Pat<(add GPR:$rs1, (AddiPair GPR:$rs2)), + (ADDI (ADDI GPR:$rs1, (AddiPairImmB GPR:$rs2)), + (AddiPairImmA GPR:$rs2))>; + //===----------------------------------------------------------------------===// // Standard extensions //===----------------------------------------------------------------------===//