Skip to content

Commit e582048

Browse files
committed
[DAG] Fold (and X, (bswap/bitreverse (not Y))) -> (and X, (not (bswap/bitreverse Y))) on ANDNOT capable targets
Fixes #112425
1 parent e839d2a commit e582048

File tree

2 files changed

+47
-44
lines changed

2 files changed

+47
-44
lines changed

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7350,6 +7350,21 @@ SDValue DAGCombiner::visitAND(SDNode *N) {
73507350
if (SDValue R = foldLogicOfShifts(N, N1, N0, DAG))
73517351
return R;
73527352

7353+
// If the target supports ANDNOT, attempt to reconstruct an ANDNOT pattern
7354+
// that might have become separated by a bitwise-agnostic instruction.
7355+
if (TLI.hasAndNot(SDValue(N, 0))) {
7356+
SDValue X, Y;
7357+
7358+
// Fold (and X, (bswap (not Y))) -> (and X, (not (bswap Y)))
7359+
// Fold (and X, (bitreverse (not Y))) -> (and X, (not (bitreverse Y)))
7360+
for (unsigned Opc : {ISD::BSWAP, ISD::BITREVERSE})
7361+
if (sd_match(N, m_And(m_Value(X),
7362+
m_OneUse(m_UnaryOp(Opc, m_Not(m_Value(Y)))))) &&
7363+
!sd_match(X, m_Not(m_Value())))
7364+
return DAG.getNode(ISD::AND, DL, VT, X,
7365+
DAG.getNOT(DL, DAG.getNode(Opc, DL, VT, Y), VT));
7366+
}
7367+
73537368
// Masking the negated extension of a boolean is just the zero-extended
73547369
// boolean:
73557370
// and (sub 0, zext(bool X)), 1 --> zext(bool X)

llvm/test/CodeGen/X86/andnot-patterns.ll

Lines changed: 32 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -321,22 +321,18 @@ define i8 @andnot_rotr_i8(i8 %a0, i8 %a1, i8 %a2) nounwind {
321321
define i64 @andnot_bswap_i64(i64 %a0, i64 %a1) nounwind {
322322
; X86-LABEL: andnot_bswap_i64:
323323
; X86: # %bb.0:
324-
; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
324+
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
325325
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
326-
; X86-NEXT: notl %eax
327-
; X86-NEXT: notl %edx
328-
; X86-NEXT: bswapl %edx
329326
; X86-NEXT: bswapl %eax
330-
; X86-NEXT: andl {{[0-9]+}}(%esp), %eax
331-
; X86-NEXT: andl {{[0-9]+}}(%esp), %edx
327+
; X86-NEXT: andnl {{[0-9]+}}(%esp), %eax, %eax
328+
; X86-NEXT: bswapl %ecx
329+
; X86-NEXT: andnl {{[0-9]+}}(%esp), %ecx, %edx
332330
; X86-NEXT: retl
333331
;
334332
; X64-LABEL: andnot_bswap_i64:
335333
; X64: # %bb.0:
336-
; X64-NEXT: movq %rsi, %rax
337-
; X64-NEXT: notq %rax
338-
; X64-NEXT: bswapq %rax
339-
; X64-NEXT: andq %rdi, %rax
334+
; X64-NEXT: bswapq %rsi
335+
; X64-NEXT: andnq %rdi, %rsi, %rax
340336
; X64-NEXT: retq
341337
%not = xor i64 %a1, -1
342338
%bswap = tail call i64 @llvm.bswap.i64(i64 %not)
@@ -348,17 +344,14 @@ define i32 @andnot_bswap_i32(i32 %a0, i32 %a1) nounwind {
348344
; X86-LABEL: andnot_bswap_i32:
349345
; X86: # %bb.0:
350346
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
351-
; X86-NEXT: notl %eax
352347
; X86-NEXT: bswapl %eax
353-
; X86-NEXT: andl {{[0-9]+}}(%esp), %eax
348+
; X86-NEXT: andnl {{[0-9]+}}(%esp), %eax, %eax
354349
; X86-NEXT: retl
355350
;
356351
; X64-LABEL: andnot_bswap_i32:
357352
; X64: # %bb.0:
358-
; X64-NEXT: movl %esi, %eax
359-
; X64-NEXT: notl %eax
360-
; X64-NEXT: bswapl %eax
361-
; X64-NEXT: andl %edi, %eax
353+
; X64-NEXT: bswapl %esi
354+
; X64-NEXT: andnl %edi, %esi, %eax
362355
; X64-NEXT: retq
363356
%not = xor i32 %a1, -1
364357
%bswap = tail call i32 @llvm.bswap.i32(i32 %not)
@@ -399,8 +392,24 @@ define i64 @andnot_bitreverse_i64(i64 %a0, i64 %a1) nounwind {
399392
; X86: # %bb.0:
400393
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
401394
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
402-
; X86-NEXT: notl %eax
403-
; X86-NEXT: notl %ecx
395+
; X86-NEXT: bswapl %eax
396+
; X86-NEXT: movl %eax, %edx
397+
; X86-NEXT: andl $252645135, %edx # imm = 0xF0F0F0F
398+
; X86-NEXT: shll $4, %edx
399+
; X86-NEXT: shrl $4, %eax
400+
; X86-NEXT: andl $252645135, %eax # imm = 0xF0F0F0F
401+
; X86-NEXT: orl %edx, %eax
402+
; X86-NEXT: movl %eax, %edx
403+
; X86-NEXT: andl $858993459, %edx # imm = 0x33333333
404+
; X86-NEXT: shrl $2, %eax
405+
; X86-NEXT: andl $858993459, %eax # imm = 0x33333333
406+
; X86-NEXT: leal (%eax,%edx,4), %eax
407+
; X86-NEXT: movl %eax, %edx
408+
; X86-NEXT: andl $1431655765, %edx # imm = 0x55555555
409+
; X86-NEXT: shrl %eax
410+
; X86-NEXT: andl $1431655765, %eax # imm = 0x55555555
411+
; X86-NEXT: leal (%eax,%edx,2), %eax
412+
; X86-NEXT: andnl {{[0-9]+}}(%esp), %eax, %eax
404413
; X86-NEXT: bswapl %ecx
405414
; X86-NEXT: movl %ecx, %edx
406415
; X86-NEXT: andl $252645135, %edx # imm = 0xF0F0F0F
@@ -417,31 +426,12 @@ define i64 @andnot_bitreverse_i64(i64 %a0, i64 %a1) nounwind {
417426
; X86-NEXT: andl $1431655765, %edx # imm = 0x55555555
418427
; X86-NEXT: shrl %ecx
419428
; X86-NEXT: andl $1431655765, %ecx # imm = 0x55555555
420-
; X86-NEXT: leal (%ecx,%edx,2), %edx
421-
; X86-NEXT: bswapl %eax
422-
; X86-NEXT: movl %eax, %ecx
423-
; X86-NEXT: andl $252645135, %ecx # imm = 0xF0F0F0F
424-
; X86-NEXT: shll $4, %ecx
425-
; X86-NEXT: shrl $4, %eax
426-
; X86-NEXT: andl $252645135, %eax # imm = 0xF0F0F0F
427-
; X86-NEXT: orl %ecx, %eax
428-
; X86-NEXT: movl %eax, %ecx
429-
; X86-NEXT: andl $858993459, %ecx # imm = 0x33333333
430-
; X86-NEXT: shrl $2, %eax
431-
; X86-NEXT: andl $858993459, %eax # imm = 0x33333333
432-
; X86-NEXT: leal (%eax,%ecx,4), %eax
433-
; X86-NEXT: movl %eax, %ecx
434-
; X86-NEXT: andl $1431655765, %ecx # imm = 0x55555555
435-
; X86-NEXT: shrl %eax
436-
; X86-NEXT: andl $1431655765, %eax # imm = 0x55555555
437-
; X86-NEXT: leal (%eax,%ecx,2), %eax
438-
; X86-NEXT: andl {{[0-9]+}}(%esp), %eax
439-
; X86-NEXT: andl {{[0-9]+}}(%esp), %edx
429+
; X86-NEXT: leal (%ecx,%edx,2), %ecx
430+
; X86-NEXT: andnl {{[0-9]+}}(%esp), %ecx, %edx
440431
; X86-NEXT: retl
441432
;
442433
; X64-LABEL: andnot_bitreverse_i64:
443434
; X64: # %bb.0:
444-
; X64-NEXT: notq %rsi
445435
; X64-NEXT: bswapq %rsi
446436
; X64-NEXT: movq %rsi, %rax
447437
; X64-NEXT: shrq $4, %rax
@@ -462,7 +452,7 @@ define i64 @andnot_bitreverse_i64(i64 %a0, i64 %a1) nounwind {
462452
; X64-NEXT: shrq %rax
463453
; X64-NEXT: andq %rcx, %rax
464454
; X64-NEXT: leaq (%rax,%rdx,2), %rax
465-
; X64-NEXT: andq %rdi, %rax
455+
; X64-NEXT: andnq %rdi, %rax, %rax
466456
; X64-NEXT: retq
467457
%not = xor i64 %a1, -1
468458
%bitrev = tail call i64 @llvm.bitreverse.i64(i64 %not)
@@ -474,7 +464,6 @@ define i32 @andnot_bitreverse_i32(i32 %a0, i32 %a1) nounwind {
474464
; X86-LABEL: andnot_bitreverse_i32:
475465
; X86: # %bb.0:
476466
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
477-
; X86-NEXT: notl %eax
478467
; X86-NEXT: bswapl %eax
479468
; X86-NEXT: movl %eax, %ecx
480469
; X86-NEXT: andl $252645135, %ecx # imm = 0xF0F0F0F
@@ -492,13 +481,12 @@ define i32 @andnot_bitreverse_i32(i32 %a0, i32 %a1) nounwind {
492481
; X86-NEXT: shrl %eax
493482
; X86-NEXT: andl $1431655765, %eax # imm = 0x55555555
494483
; X86-NEXT: leal (%eax,%ecx,2), %eax
495-
; X86-NEXT: andl {{[0-9]+}}(%esp), %eax
484+
; X86-NEXT: andnl {{[0-9]+}}(%esp), %eax, %eax
496485
; X86-NEXT: retl
497486
;
498487
; X64-LABEL: andnot_bitreverse_i32:
499488
; X64: # %bb.0:
500489
; X64-NEXT: # kill: def $esi killed $esi def $rsi
501-
; X64-NEXT: notl %esi
502490
; X64-NEXT: bswapl %esi
503491
; X64-NEXT: movl %esi, %eax
504492
; X64-NEXT: andl $252645135, %eax # imm = 0xF0F0F0F
@@ -516,7 +504,7 @@ define i32 @andnot_bitreverse_i32(i32 %a0, i32 %a1) nounwind {
516504
; X64-NEXT: shrl %eax
517505
; X64-NEXT: andl $1431655765, %eax # imm = 0x55555555
518506
; X64-NEXT: leal (%rax,%rcx,2), %eax
519-
; X64-NEXT: andl %edi, %eax
507+
; X64-NEXT: andnl %edi, %eax, %eax
520508
; X64-NEXT: retq
521509
%not = xor i32 %a1, -1
522510
%bitrev = tail call i32 @llvm.bitreverse.i32(i32 %not)

0 commit comments

Comments
 (0)