diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 6aa86741dcc1d..6adce8877ef50 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -21127,9 +21127,14 @@ bool RISCVTargetLowering::isDesirableToCommuteWithShift( auto *C1 = dyn_cast(N0->getOperand(1)); auto *C2 = dyn_cast(N->getOperand(1)); - // Bail if we might break a sh{1,2,3}add pattern. - if ((Subtarget.hasStdExtZba() || Subtarget.hasVendorXAndesPerf()) && C2 && - C2->getZExtValue() >= 1 && C2->getZExtValue() <= 3 && N->hasOneUse() && + bool IsShXAdd = + (Subtarget.hasStdExtZba() || Subtarget.hasVendorXAndesPerf()) && C2 && + C2->getZExtValue() >= 1 && C2->getZExtValue() <= 3; + bool IsQCShlAdd = Subtarget.hasVendorXqciac() && C2 && + C2->getZExtValue() >= 4 && C2->getZExtValue() <= 31; + + // Bail if we might break a sh{1,2,3}add/qc.shladd pattern. + if ((IsShXAdd || IsQCShlAdd) && N->hasOneUse() && N->user_begin()->getOpcode() == ISD::ADD && !isUsedByLdSt(*N->user_begin(), nullptr) && !isa(N->user_begin()->getOperand(1))) diff --git a/llvm/test/CodeGen/RISCV/xqciac.ll b/llvm/test/CodeGen/RISCV/xqciac.ll index 6fdc63fddbc30..934deb5a0c327 100644 --- a/llvm/test/CodeGen/RISCV/xqciac.ll +++ b/llvm/test/CodeGen/RISCV/xqciac.ll @@ -490,3 +490,112 @@ define i32 @testmuliaddnegimm(i32 %a) { %add = add i32 %mul, 3 ret i32 %add } + +define i32 @add_shl_OneUse_1(i32 %x) { +; RV32IM-LABEL: add_shl_OneUse_1: +; RV32IM: # %bb.0: +; RV32IM-NEXT: ori a1, a0, 1 +; RV32IM-NEXT: slli a0, a0, 4 +; RV32IM-NEXT: ori a0, a0, 16 +; RV32IM-NEXT: add a0, a0, a1 +; RV32IM-NEXT: ret +; +; RV32IMXQCIAC-LABEL: add_shl_OneUse_1: +; RV32IMXQCIAC: # %bb.0: +; RV32IMXQCIAC-NEXT: ori a0, a0, 1 +; RV32IMXQCIAC-NEXT: qc.shladd a0, a0, a0, 4 +; RV32IMXQCIAC-NEXT: ret +; +; RV32IZBAMXQCIAC-LABEL: add_shl_OneUse_1: +; RV32IZBAMXQCIAC: # %bb.0: +; RV32IZBAMXQCIAC-NEXT: ori a0, a0, 1 +; RV32IZBAMXQCIAC-NEXT: qc.shladd a0, a0, a0, 4 +; RV32IZBAMXQCIAC-NEXT: ret + %or = or i32 %x, 1 + %mul = shl i32 %or, 4 + %add = add i32 %mul, %or + ret i32 %add +} + +define i32 @add_shl_OneUse_2(i32 %x) { +; RV32IM-LABEL: add_shl_OneUse_2: +; RV32IM: # %bb.0: +; RV32IM-NEXT: ori a1, a0, 1 +; RV32IM-NEXT: slli a0, a0, 10 +; RV32IM-NEXT: ori a0, a0, 1024 +; RV32IM-NEXT: add a0, a0, a1 +; RV32IM-NEXT: ret +; +; RV32IMXQCIAC-LABEL: add_shl_OneUse_2: +; RV32IMXQCIAC: # %bb.0: +; RV32IMXQCIAC-NEXT: ori a0, a0, 1 +; RV32IMXQCIAC-NEXT: qc.shladd a0, a0, a0, 10 +; RV32IMXQCIAC-NEXT: ret +; +; RV32IZBAMXQCIAC-LABEL: add_shl_OneUse_2: +; RV32IZBAMXQCIAC: # %bb.0: +; RV32IZBAMXQCIAC-NEXT: ori a0, a0, 1 +; RV32IZBAMXQCIAC-NEXT: qc.shladd a0, a0, a0, 10 +; RV32IZBAMXQCIAC-NEXT: ret + %or = or i32 %x, 1 + %mul = shl i32 %or, 10 + %add = add i32 %mul, %or + ret i32 %add +} + +; For shifts greater than 10 the ori immediate cannot fit within 12 bits so +; we don't commute with shift and generate qc.shaldd +define i32 @add_shl_OneUse_3(i32 %x) { +; RV32IM-LABEL: add_shl_OneUse_3: +; RV32IM: # %bb.0: +; RV32IM-NEXT: ori a0, a0, 1 +; RV32IM-NEXT: slli a1, a0, 11 +; RV32IM-NEXT: add a0, a1, a0 +; RV32IM-NEXT: ret +; +; RV32IMXQCIAC-LABEL: add_shl_OneUse_3: +; RV32IMXQCIAC: # %bb.0: +; RV32IMXQCIAC-NEXT: ori a0, a0, 1 +; RV32IMXQCIAC-NEXT: qc.shladd a0, a0, a0, 11 +; RV32IMXQCIAC-NEXT: ret +; +; RV32IZBAMXQCIAC-LABEL: add_shl_OneUse_3: +; RV32IZBAMXQCIAC: # %bb.0: +; RV32IZBAMXQCIAC-NEXT: ori a0, a0, 1 +; RV32IZBAMXQCIAC-NEXT: qc.shladd a0, a0, a0, 11 +; RV32IZBAMXQCIAC-NEXT: ret + %or = or i32 %x, 1 + %mul = shl i32 %or, 11 + %add = add i32 %mul, %or + ret i32 %add +} + +; The shift left gets converted early and as a result we cannot +; generate the qc.shladd. +; FIXME: Should we handle this case and generate qc.shladd if possible? +define i32 @add_shl_moreOneUse_4(i32 %x) { +; RV32IM-LABEL: add_shl_moreOneUse_4: +; RV32IM: # %bb.0: +; RV32IM-NEXT: ori a0, a0, 7 +; RV32IM-NEXT: lui a1, 524288 +; RV32IM-NEXT: add a0, a0, a1 +; RV32IM-NEXT: ret +; +; RV32IMXQCIAC-LABEL: add_shl_moreOneUse_4: +; RV32IMXQCIAC: # %bb.0: +; RV32IMXQCIAC-NEXT: ori a0, a0, 7 +; RV32IMXQCIAC-NEXT: lui a1, 524288 +; RV32IMXQCIAC-NEXT: add a0, a0, a1 +; RV32IMXQCIAC-NEXT: ret +; +; RV32IZBAMXQCIAC-LABEL: add_shl_moreOneUse_4: +; RV32IZBAMXQCIAC: # %bb.0: +; RV32IZBAMXQCIAC-NEXT: ori a0, a0, 7 +; RV32IZBAMXQCIAC-NEXT: lui a1, 524288 +; RV32IZBAMXQCIAC-NEXT: add a0, a0, a1 +; RV32IZBAMXQCIAC-NEXT: ret + %or = or i32 %x, 7 + %mul = shl i32 %or, 31 + %add = add i32 %mul, %or + ret i32 %add +}