Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,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,
Expand Down Expand Up @@ -223,6 +259,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:
Expand Down
106 changes: 106 additions & 0 deletions llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good and has a further potential for combining into addiw a0, a0, -3.

; 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
}
Loading