Skip to content

Commit 301259a

Browse files
authored
[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.
1 parent 87bd782 commit 301259a

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,42 @@ static bool canUseShiftPair(Instruction *Inst, const APInt &Imm) {
167167
return false;
168168
}
169169

170+
// If this is i64 AND is part of (X & -(1 << C1) & 0xffffffff) == C2 << C1),
171+
// DAGCombiner can convert this to (sraiw X, C1) == sext(C2) for RV64. On RV32,
172+
// the type will be split so only the lower 32 bits need to be compared using
173+
// (srai/srli X, C) == C2.
174+
static bool canUseShiftCmp(Instruction *Inst, const APInt &Imm) {
175+
if (!Inst->hasOneUse())
176+
return false;
177+
178+
// Look for equality comparison.
179+
auto *Cmp = dyn_cast<ICmpInst>(*Inst->user_begin());
180+
if (!Cmp || !Cmp->isEquality())
181+
return false;
182+
183+
// Right hand side of comparison should be a constant.
184+
auto *C = dyn_cast<ConstantInt>(Cmp->getOperand(1));
185+
if (!C)
186+
return false;
187+
188+
uint64_t Mask = Imm.getZExtValue();
189+
190+
// Mask should be of the form -(1 << C) in the lower 32 bits.
191+
if (!isUInt<32>(Mask) || !isPowerOf2_32(-uint32_t(Mask)))
192+
return false;
193+
194+
// Comparison constant should be a subset of Mask.
195+
uint64_t CmpC = C->getZExtValue();
196+
if ((CmpC & Mask) != CmpC)
197+
return false;
198+
199+
// We'll need to sign extend the comparison constant and shift it right. Make
200+
// sure the new constant can use addi/xori+seqz/snez.
201+
unsigned ShiftBits = llvm::countr_zero(Mask);
202+
int64_t NewCmpC = SignExtend64<32>(CmpC) >> ShiftBits;
203+
return NewCmpC >= -2048 && NewCmpC <= 2048;
204+
}
205+
170206
InstructionCost RISCVTTIImpl::getIntImmCostInst(unsigned Opcode, unsigned Idx,
171207
const APInt &Imm, Type *Ty,
172208
TTI::TargetCostKind CostKind,
@@ -224,6 +260,9 @@ InstructionCost RISCVTTIImpl::getIntImmCostInst(unsigned Opcode, unsigned Idx,
224260
if (Inst && Idx == 1 && Imm.getBitWidth() <= ST->getXLen() &&
225261
canUseShiftPair(Inst, Imm))
226262
return TTI::TCC_Free;
263+
if (Inst && Idx == 1 && Imm.getBitWidth() == 64 &&
264+
canUseShiftCmp(Inst, Imm))
265+
return TTI::TCC_Free;
227266
Takes12BitImm = true;
228267
break;
229268
case Instruction::Add:

llvm/test/CodeGen/RISCV/and-negpow2-cmp.ll

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,109 @@ define i1 @test9(i64 %x) {
155155
%b = icmp eq i64 %a, u0x08000000
156156
ret i1 %b
157157
}
158+
159+
; Make sure the and constant doesn't get converted to an opaque constant by
160+
; ConstantHoisting. If it's an opaque constant, we'll have addi -16 and addi 15.
161+
define i64 @test10(i64 %0) #0 {
162+
; RV32-LABEL: test10:
163+
; RV32: # %bb.0: # %entry
164+
; RV32-NEXT: addi a0, a0, -1
165+
; RV32-NEXT: andi a0, a0, -16
166+
; RV32-NEXT: snez a0, a0
167+
; RV32-NEXT: li a1, 0
168+
; RV32-NEXT: ret
169+
;
170+
; RV64-LABEL: test10:
171+
; RV64: # %bb.0: # %entry
172+
; RV64-NEXT: addi a0, a0, -1
173+
; RV64-NEXT: sraiw a0, a0, 4
174+
; RV64-NEXT: snez a0, a0
175+
; RV64-NEXT: ret
176+
entry:
177+
%1 = add nuw nsw i64 %0, u0xffffffff
178+
%2 = and i64 %1, u0xfffffff0
179+
%3 = icmp ne i64 %2, 0
180+
%4 = zext i1 %3 to i64
181+
ret i64 %4
182+
}
183+
184+
; Make sure the and constant doesn't get converted to an opaque constant by
185+
; ConstantHoisting. If it's an opaque constant, we'll have addi -16 and addi 15.
186+
define i64 @test11(i64 %0) #0 {
187+
; RV32-LABEL: test11:
188+
; RV32: # %bb.0: # %entry
189+
; RV32-NEXT: addi a0, a0, -1
190+
; RV32-NEXT: srai a0, a0, 4
191+
; RV32-NEXT: addi a0, a0, 1621
192+
; RV32-NEXT: seqz a0, a0
193+
; RV32-NEXT: li a1, 0
194+
; RV32-NEXT: ret
195+
;
196+
; RV64-LABEL: test11:
197+
; RV64: # %bb.0: # %entry
198+
; RV64-NEXT: addi a0, a0, -1
199+
; RV64-NEXT: sraiw a0, a0, 4
200+
; RV64-NEXT: addi a0, a0, 1621
201+
; RV64-NEXT: seqz a0, a0
202+
; RV64-NEXT: ret
203+
entry:
204+
%1 = add nuw nsw i64 %0, u0xffffffff
205+
%2 = and i64 %1, u0xfffffff0
206+
%3 = icmp eq i64 %2, u0xffff9ab0
207+
%4 = zext i1 %3 to i64
208+
ret i64 %4
209+
}
210+
211+
; Make sure the and constant doesn't get converted to an opaque constant by
212+
; ConstantHoisting. If it's an opaque constant we'll end up with constant
213+
; materialization sequences on RV64.
214+
define i64 @test12(i64 %0) #0 {
215+
; RV32-LABEL: test12:
216+
; RV32: # %bb.0: # %entry
217+
; RV32-NEXT: addi a0, a0, -3
218+
; RV32-NEXT: seqz a0, a0
219+
; RV32-NEXT: li a1, 0
220+
; RV32-NEXT: ret
221+
;
222+
; RV64-LABEL: test12:
223+
; RV64: # %bb.0: # %entry
224+
; RV64-NEXT: addiw a0, a0, -16
225+
; RV64-NEXT: addi a0, a0, 13
226+
; RV64-NEXT: seqz a0, a0
227+
; RV64-NEXT: ret
228+
entry:
229+
%1 = add nuw nsw i64 %0, u0xfffffff0
230+
%2 = and i64 %1, u0xffffffff
231+
%3 = icmp eq i64 %2, u0xfffffff3
232+
%4 = zext i1 %3 to i64
233+
ret i64 %4
234+
}
235+
236+
; Make sure the and constant doesn't get converted to an opaque constant by
237+
; ConstantHoisting.
238+
define i64 @test13(i64 %0) #0 {
239+
; RV32-LABEL: test13:
240+
; RV32: # %bb.0: # %entry
241+
; RV32-NEXT: lui a1, 524288
242+
; RV32-NEXT: addi a1, a1, 15
243+
; RV32-NEXT: add a0, a0, a1
244+
; RV32-NEXT: srli a0, a0, 31
245+
; RV32-NEXT: seqz a0, a0
246+
; RV32-NEXT: li a1, 0
247+
; RV32-NEXT: ret
248+
;
249+
; RV64-LABEL: test13:
250+
; RV64: # %bb.0: # %entry
251+
; RV64-NEXT: lui a1, 524288
252+
; RV64-NEXT: addi a1, a1, -15
253+
; RV64-NEXT: sub a0, a0, a1
254+
; RV64-NEXT: sraiw a0, a0, 31
255+
; RV64-NEXT: seqz a0, a0
256+
; RV64-NEXT: ret
257+
entry:
258+
%1 = add nuw nsw i64 %0, u0x8000000f
259+
%2 = and i64 %1, u0x80000000
260+
%3 = icmp eq i64 %2, 0
261+
%4 = zext i1 %3 to i64
262+
ret i64 %4
263+
}

0 commit comments

Comments
 (0)