[llvm] 301259a - [RISCV] Teach getIntImmCostInst about (X & -(1 << C1) & 0xffffffff) == C2 << C1 (#160163)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 29 10:36:30 PDT 2025
Author: Craig Topper
Date: 2025-09-29T10:36:27-07:00
New Revision: 301259a6b1c8146a185e7c1bea46ec02d028243e
URL: https://github.com/llvm/llvm-project/commit/301259a6b1c8146a185e7c1bea46ec02d028243e
DIFF: https://github.com/llvm/llvm-project/commit/301259a6b1c8146a185e7c1bea46ec02d028243e.diff
LOG: [RISCV] Teach getIntImmCostInst about (X & -(1 << C1) & 0xffffffff) == C2 << C1 (#160163)
We can rewrite this to (srai(w)/srli X, C1) == C2 so the AND immediate
is free. This transform is done by performSETCCCombine in
RISCVISelLowering.cpp.
This fixes the opaque constant case mentioned in #157416.
Added:
Modified:
llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
index 563f3bbee81df..d4124ae9aeff0 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
@@ -167,6 +167,42 @@ static bool canUseShiftPair(Instruction *Inst, const APInt &Imm) {
return false;
}
+// If this is i64 AND is part of (X & -(1 << C1) & 0xffffffff) == C2 << C1),
+// DAGCombiner can convert this to (sraiw X, C1) == sext(C2) for RV64. On RV32,
+// the type will be split so only the lower 32 bits need to be compared using
+// (srai/srli X, C) == C2.
+static bool canUseShiftCmp(Instruction *Inst, const APInt &Imm) {
+ if (!Inst->hasOneUse())
+ return false;
+
+ // Look for equality comparison.
+ auto *Cmp = dyn_cast<ICmpInst>(*Inst->user_begin());
+ if (!Cmp || !Cmp->isEquality())
+ return false;
+
+ // Right hand side of comparison should be a constant.
+ auto *C = dyn_cast<ConstantInt>(Cmp->getOperand(1));
+ if (!C)
+ return false;
+
+ uint64_t Mask = Imm.getZExtValue();
+
+ // Mask should be of the form -(1 << C) in the lower 32 bits.
+ if (!isUInt<32>(Mask) || !isPowerOf2_32(-uint32_t(Mask)))
+ return false;
+
+ // Comparison constant should be a subset of Mask.
+ uint64_t CmpC = C->getZExtValue();
+ if ((CmpC & Mask) != CmpC)
+ return false;
+
+ // We'll need to sign extend the comparison constant and shift it right. Make
+ // sure the new constant can use addi/xori+seqz/snez.
+ unsigned ShiftBits = llvm::countr_zero(Mask);
+ int64_t NewCmpC = SignExtend64<32>(CmpC) >> ShiftBits;
+ return NewCmpC >= -2048 && NewCmpC <= 2048;
+}
+
InstructionCost RISCVTTIImpl::getIntImmCostInst(unsigned Opcode, unsigned Idx,
const APInt &Imm, Type *Ty,
TTI::TargetCostKind CostKind,
@@ -224,6 +260,9 @@ InstructionCost RISCVTTIImpl::getIntImmCostInst(unsigned Opcode, unsigned Idx,
if (Inst && Idx == 1 && Imm.getBitWidth() <= ST->getXLen() &&
canUseShiftPair(Inst, Imm))
return TTI::TCC_Free;
+ if (Inst && Idx == 1 && Imm.getBitWidth() == 64 &&
+ canUseShiftCmp(Inst, Imm))
+ return TTI::TCC_Free;
Takes12BitImm = true;
break;
case Instruction::Add:
diff --git a/llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll b/llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll
index 55b0d1f0bf7be..2a46a59e90535 100644
--- a/llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll
+++ b/llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll
@@ -155,3 +155,109 @@ define i1 @test9(i64 %x) {
%b = icmp eq i64 %a, u0x08000000
ret i1 %b
}
+
+; Make sure the and constant doesn't get converted to an opaque constant by
+; ConstantHoisting. If it's an opaque constant, we'll have addi -16 and addi 15.
+define i64 @test10(i64 %0) #0 {
+; RV32-LABEL: test10:
+; RV32: # %bb.0: # %entry
+; RV32-NEXT: addi a0, a0, -1
+; RV32-NEXT: andi a0, a0, -16
+; RV32-NEXT: snez a0, a0
+; RV32-NEXT: li a1, 0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test10:
+; RV64: # %bb.0: # %entry
+; RV64-NEXT: addi a0, a0, -1
+; RV64-NEXT: sraiw a0, a0, 4
+; RV64-NEXT: snez a0, a0
+; RV64-NEXT: ret
+entry:
+ %1 = add nuw nsw i64 %0, u0xffffffff
+ %2 = and i64 %1, u0xfffffff0
+ %3 = icmp ne i64 %2, 0
+ %4 = zext i1 %3 to i64
+ ret i64 %4
+}
+
+; Make sure the and constant doesn't get converted to an opaque constant by
+; ConstantHoisting. If it's an opaque constant, we'll have addi -16 and addi 15.
+define i64 @test11(i64 %0) #0 {
+; RV32-LABEL: test11:
+; RV32: # %bb.0: # %entry
+; RV32-NEXT: addi a0, a0, -1
+; RV32-NEXT: srai a0, a0, 4
+; RV32-NEXT: addi a0, a0, 1621
+; RV32-NEXT: seqz a0, a0
+; RV32-NEXT: li a1, 0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test11:
+; RV64: # %bb.0: # %entry
+; RV64-NEXT: addi a0, a0, -1
+; RV64-NEXT: sraiw a0, a0, 4
+; RV64-NEXT: addi a0, a0, 1621
+; RV64-NEXT: seqz a0, a0
+; RV64-NEXT: ret
+entry:
+ %1 = add nuw nsw i64 %0, u0xffffffff
+ %2 = and i64 %1, u0xfffffff0
+ %3 = icmp eq i64 %2, u0xffff9ab0
+ %4 = zext i1 %3 to i64
+ ret i64 %4
+}
+
+; Make sure the and constant doesn't get converted to an opaque constant by
+; ConstantHoisting. If it's an opaque constant we'll end up with constant
+; materialization sequences on RV64.
+define i64 @test12(i64 %0) #0 {
+; RV32-LABEL: test12:
+; RV32: # %bb.0: # %entry
+; RV32-NEXT: addi a0, a0, -3
+; RV32-NEXT: seqz a0, a0
+; RV32-NEXT: li a1, 0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test12:
+; RV64: # %bb.0: # %entry
+; RV64-NEXT: addiw a0, a0, -16
+; RV64-NEXT: addi a0, a0, 13
+; RV64-NEXT: seqz a0, a0
+; RV64-NEXT: ret
+entry:
+ %1 = add nuw nsw i64 %0, u0xfffffff0
+ %2 = and i64 %1, u0xffffffff
+ %3 = icmp eq i64 %2, u0xfffffff3
+ %4 = zext i1 %3 to i64
+ ret i64 %4
+}
+
+; Make sure the and constant doesn't get converted to an opaque constant by
+; ConstantHoisting.
+define i64 @test13(i64 %0) #0 {
+; RV32-LABEL: test13:
+; RV32: # %bb.0: # %entry
+; RV32-NEXT: lui a1, 524288
+; RV32-NEXT: addi a1, a1, 15
+; RV32-NEXT: add a0, a0, a1
+; RV32-NEXT: srli a0, a0, 31
+; RV32-NEXT: seqz a0, a0
+; RV32-NEXT: li a1, 0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: test13:
+; RV64: # %bb.0: # %entry
+; RV64-NEXT: lui a1, 524288
+; RV64-NEXT: addi a1, a1, -15
+; RV64-NEXT: sub a0, a0, a1
+; RV64-NEXT: sraiw a0, a0, 31
+; RV64-NEXT: seqz a0, a0
+; RV64-NEXT: ret
+entry:
+ %1 = add nuw nsw i64 %0, u0x8000000f
+ %2 = and i64 %1, u0x80000000
+ %3 = icmp eq i64 %2, 0
+ %4 = zext i1 %3 to i64
+ ret i64 %4
+}
More information about the llvm-commits
mailing list