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 @@ -74,6 +74,32 @@ EVT VT = Node->getValueType(0); switch (Opcode) { + // Optimize the node (add r, imm) to (addi (addi r, imm0) imm1) + // if possible. + case ISD::ADD: { + // The second operand must be an immediate. + if (auto *ConstOp = dyn_cast(Node->getOperand(1))) { + // The immediate operand must not have other use. + if (!ConstOp->hasOneUse()) + break; + // The immediate must be in range [-4095,-2049] or [2048,4094]. + int64_t ImmVal = ConstOp->getSExtValue(); + if (ImmVal < -4095 || (-2049 < ImmVal && ImmVal < 2048) || 4094 < ImmVal) + break; + // Break the immediate to Imm0+Imm1. + SDLoc DL(Node); + EVT VT = Node->getValueType(0); + SDValue ImmOp0 = CurDAG->getTargetConstant(ImmVal / 2, DL, VT); + SDValue ImmOp1 = CurDAG->getTargetConstant(ImmVal - ImmVal / 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()) { diff --git a/llvm/test/CodeGen/RISCV/add-imm.ll b/llvm/test/CodeGen/RISCV/add-imm.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/add-imm.ll @@ -0,0 +1,165 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32I %s +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64I %s + +; These test how the immediate in an addition is materialized. + +define i32 @add32_0(i32 %a) nounwind { +; RV32I-LABEL: add32_0: +; RV32I: # %bb.0: +; RV32I-NEXT: addi a0, a0, 2047 +; RV32I-NEXT: ret + %1 = add i32 %a, 2047 + ret i32 %1 +} + +define i64 @add64_0(i64 %a) nounwind { +; RV64I-LABEL: add64_0: +; RV64I: # %bb.0: +; RV64I-NEXT: addi a0, a0, 2047 +; RV64I-NEXT: ret + %1 = add i64 %a, 2047 + ret i64 %1 +} + +define i32 @add32_1(i32 %a) nounwind { +; RV32I-LABEL: add32_1: +; RV32I: # %bb.0: +; RV32I-NEXT: addi a0, a0, 1024 +; RV32I-NEXT: addi a0, a0, 1024 +; RV32I-NEXT: ret + %1 = add i32 %a, 2048 + ret i32 %1 +} + +define i64 @add64_1(i64 %a) nounwind { +; RV64I-LABEL: add64_1: +; RV64I: # %bb.0: +; RV64I-NEXT: addi a0, a0, 1024 +; RV64I-NEXT: addi a0, a0, 1024 +; RV64I-NEXT: ret + %1 = add i64 %a, 2048 + ret i64 %1 +} + +define i32 @add32_2(i32 %a) nounwind { +; RV32I-LABEL: add32_2: +; RV32I: # %bb.0: +; RV32I-NEXT: addi a0, a0, 2047 +; RV32I-NEXT: addi a0, a0, 2047 +; RV32I-NEXT: ret + %1 = add i32 %a, 4094 + ret i32 %1 +} + +define i64 @add64_2(i64 %a) nounwind { +; RV64I-LABEL: add64_2: +; RV64I: # %bb.0: +; RV64I-NEXT: addi a0, a0, 2047 +; RV64I-NEXT: addi a0, a0, 2047 +; RV64I-NEXT: ret + %1 = add i64 %a, 4094 + ret i64 %1 +} + +define i32 @add32_3(i32 %a) nounwind { +; RV32I-LABEL: add32_3: +; RV32I: # %bb.0: +; RV32I-NEXT: lui a1, 1 +; RV32I-NEXT: addi a1, a1, -1 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: ret + %1 = add i32 %a, 4095 + ret i32 %1 +} + +define i64 @add64_3(i64 %a) nounwind { +; RV64I-LABEL: add64_3: +; RV64I: # %bb.0: +; RV64I-NEXT: lui a1, 1 +; RV64I-NEXT: addiw a1, a1, -1 +; RV64I-NEXT: add a0, a0, a1 +; RV64I-NEXT: ret + %1 = add i64 %a, 4095 + ret i64 %1 +} + +define i32 @add32_4(i32 %a) nounwind { +; RV32I-LABEL: add32_4: +; RV32I: # %bb.0: +; RV32I-NEXT: addi a0, a0, -2048 +; RV32I-NEXT: ret + %1 = add i32 %a, -2048 + ret i32 %1 +} + +define i64 @add64_4(i64 %a) nounwind { +; RV64I-LABEL: add64_4: +; RV64I: # %bb.0: +; RV64I-NEXT: addi a0, a0, -2048 +; RV64I-NEXT: ret + %1 = add i64 %a, -2048 + ret i64 %1 +} + +define i32 @add32_5(i32 %a) nounwind { +; RV32I-LABEL: add32_5: +; RV32I: # %bb.0: +; RV32I-NEXT: addi a0, a0, -1024 +; RV32I-NEXT: addi a0, a0, -1025 +; RV32I-NEXT: ret + %1 = add i32 %a, -2049 + ret i32 %1 +} + +define i64 @add64_5(i64 %a) nounwind { +; RV64I-LABEL: add64_5: +; RV64I: # %bb.0: +; RV64I-NEXT: addi a0, a0, -1024 +; RV64I-NEXT: addi a0, a0, -1025 +; RV64I-NEXT: ret + %1 = add i64 %a, -2049 + ret i64 %1 +} + +define i32 @add32_6(i32 %a) nounwind { +; RV32I-LABEL: add32_6: +; RV32I: # %bb.0: +; RV32I-NEXT: addi a0, a0, -2047 +; RV32I-NEXT: addi a0, a0, -2048 +; RV32I-NEXT: ret + %1 = add i32 %a, -4095 + ret i32 %1 +} + +define i64 @add64_6(i64 %a) nounwind { +; RV64I-LABEL: add64_6: +; RV64I: # %bb.0: +; RV64I-NEXT: addi a0, a0, -2047 +; RV64I-NEXT: addi a0, a0, -2048 +; RV64I-NEXT: ret + %1 = add i64 %a, -4095 + ret i64 %1 +} + +define i32 @add32_7(i32 %a) nounwind { +; RV32I-LABEL: add32_7: +; RV32I: # %bb.0: +; RV32I-NEXT: lui a1, 1048575 +; RV32I-NEXT: add a0, a0, a1 +; RV32I-NEXT: ret + %1 = add i32 %a, -4096 + ret i32 %1 +} + +define i64 @add64_7(i64 %a) nounwind { +; RV64I-LABEL: add64_7: +; RV64I: # %bb.0: +; RV64I-NEXT: lui a1, 1048575 +; RV64I-NEXT: add a0, a0, a1 +; RV64I-NEXT: ret + %1 = add i64 %a, -4096 + ret i64 %1 +}