; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc --mtriple=loongarch32 -mattr=+d < %s | FileCheck %s
;; Test generation of the bstrins.w instruction.
;; There are 8 patterns that can be matched to bstrins.w. See performORCombine
;; for details.
;; Pattern 1
;; R = or (and X, mask0), (and (shl Y, lsb), mask1)
;; =>
;; R = BSTRINS X, Y, msb, lsb
define i32 @pat1(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: pat1:
; CHECK: # %bb.0:
; CHECK-NEXT: bstrins.w $a0, $a1, 19, 8
; CHECK-NEXT: ret
%and1 = and i32 %a, -1048321 ; 0xfff000ff
%shl = shl i32 %b, 8
%and2 = and i32 %shl, 1048320 ; 0x000fff00
%or = or i32 %and1, %and2
ret i32 %or
}
define i32 @pat1_swap(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: pat1_swap:
; CHECK: # %bb.0:
; CHECK-NEXT: bstrins.w $a0, $a1, 19, 8
; CHECK-NEXT: ret
%and1 = and i32 %a, -1048321 ; 0xfff000ff
%shl = shl i32 %b, 8
%and2 = and i32 %shl, 1048320 ; 0x000fff00
%or = or i32 %and2, %and1
ret i32 %or
}
;; Pattern 2
;; R = or (and X, mask0), (shl (and Y, mask1), lsb)
;; =>
;; R = BSTRINS X, Y, msb, lsb
define i32 @pat2(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: pat2:
; CHECK: # %bb.0:
; CHECK-NEXT: bstrins.w $a0, $a1, 19, 8
; CHECK-NEXT: ret
%and1 = and i32 %a, -1048321 ; 0xfff000ff
%and2 = and i32 %b, 4095 ; 0x00000fff
%shl = shl i32 %and2, 8
%or = or i32 %and1, %shl
ret i32 %or
}
define i32 @pat2_swap(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: pat2_swap:
; CHECK: # %bb.0:
; CHECK-NEXT: bstrins.w $a0, $a1, 19, 8
; CHECK-NEXT: ret
%and1 = and i32 %a, -1048321 ; 0xfff000ff
%and2 = and i32 %b, 4095 ; 0x00000fff
%shl = shl i32 %and2, 8
%or = or i32 %shl, %and1
ret i32 %or
}
;; Pattern 3
;; R = or (and X, mask0), (and Y, mask1)
;; =>
;; R = BSTRINS X, (srl (and Y, mask1), lsb), msb, lsb
define i32 @pat3(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: pat3:
; CHECK: # %bb.0:
; CHECK-NEXT: andi $a1, $a1, 288
; CHECK-NEXT: srli.w $a1, $a1, 4
; CHECK-NEXT: bstrins.w $a0, $a1, 11, 4
; CHECK-NEXT: ret
%and1 = and i32 %a, -4081 ; 0xfffff00f
%and2 = and i32 %b, 288 ; 0x00000120
%or = or i32 %and1, %and2
ret i32 %or
}
define i32 @pat3_swap(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: pat3_swap:
; CHECK: # %bb.0:
; CHECK-NEXT: andi $a1, $a1, 288
; CHECK-NEXT: srli.w $a1, $a1, 4
; CHECK-NEXT: bstrins.w $a0, $a1, 11, 4
; CHECK-NEXT: ret
%and1 = and i32 %a, -4081 ; 0xfffff00f
%and2 = and i32 %b, 288 ; 0x00000120
%or = or i32 %and2, %and1
ret i32 %or
}
define i32 @pat3_positive_mask0(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: pat3_positive_mask0:
; CHECK: # %bb.0:
; CHECK-NEXT: srli.w $a1, $a1, 28
; CHECK-NEXT: bstrins.w $a0, $a1, 31, 28
; CHECK-NEXT: ret
%and1 = and i32 %a, 268435455 ; 0x0fffffff
%and2 = and i32 %b, 4026531840 ; 0xf0000000
%or = or i32 %and1, %and2
ret i32 %or
}
;; Pattern 4
;; R = or (and X, mask), (shl Y, shamt)
;; =>
;; R = BSTRINS X, Y, 31, shamt
define i32 @pat4(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: pat4:
; CHECK: # %bb.0:
; CHECK-NEXT: bstrins.w $a0, $a1, 31, 28
; CHECK-NEXT: ret
%and = and i32 %a, 268435455 ; 0x0fffffff
%shl = shl i32 %b, 28
%or = or i32 %and, %shl
ret i32 %or
}
define i32 @pat4_swap(i32 %a, i32 %b) nounwind {
; CHECK-LABEL: pat4_swap:
; CHECK: # %bb.0:
; CHECK-NEXT: bstrins.w $a0, $a1, 31, 28
; CHECK-NEXT: ret
%and = and i32 %a, 268435455 ; 0x0fffffff
%shl = shl i32 %b, 28
%or = or i32 %shl, %and
ret i32 %or
}
;; Pattern 5
;; R = or (and X, mask), const
;; =>
;; R = BSTRINS X, (const >> lsb), msb, lsb
define i32 @pat5(i32 %a) nounwind {
; CHECK-LABEL: pat5:
; CHECK: # %bb.0:
; CHECK-NEXT: lu12i.w $a1, 1
; CHECK-NEXT: ori $a1, $a1, 564
; CHECK-NEXT: bstrins.w $a0, $a1, 23, 8
; CHECK-NEXT: ret
%and = and i32 %a, 4278190335 ; 0xff0000ff
%or = or i32 %and, 1192960 ; 0x00123400
ret i32 %or
}
;; The high bits of `const` are zero.
define i32 @pat5_high_zeros(i32 %a) nounwind {
; CHECK-LABEL: pat5_high_zeros:
; CHECK: # %bb.0:
; CHECK-NEXT: lu12i.w $a1, 1
; CHECK-NEXT: ori $a1, $a1, 564
; CHECK-NEXT: bstrins.w $a0, $a1, 31, 16
; CHECK-NEXT: ret
%and = and i32 %a, 65535 ; 0x0000ffff
%or = or i32 %and, 305397760 ; 0x12340000
ret i32 %or
}
;; Pattern 6: a = b | ((c & mask) << shamt)
;; In this testcase b is 0x10000002, but in fact we do not require b being a
;; constant. As long as all positions in b to be overwritten by the incoming
;; bits are known to be zero, the pattern could be matched.
define i32 @pat6(i32 %c) nounwind {
; CHECK-LABEL: pat6:
; CHECK: # %bb.0:
; CHECK-NEXT: lu12i.w $a1, 65536
; CHECK-NEXT: ori $a1, $a1, 2
; CHECK-NEXT: bstrins.w $a1, $a0, 27, 4
; CHECK-NEXT: move $a0, $a1
; CHECK-NEXT: ret
%and = and i32 %c, 16777215 ; 0x00ffffff
%shl = shl i32 %and, 4
%or = or i32 %shl, 268435458 ; 0x10000002
ret i32 %or
}
;; Pattern 7: a = b | ((c << shamt) & shifted_mask)
;; Similar to pattern 6.
define i32 @pat7(i32 %c) nounwind {
; CHECK-LABEL: pat7:
; CHECK: # %bb.0:
; CHECK-NEXT: lu12i.w $a1, 65536
; CHECK-NEXT: ori $a1, $a1, 2
; CHECK-NEXT: bstrins.w $a1, $a0, 27, 4
; CHECK-NEXT: move $a0, $a1
; CHECK-NEXT: ret
%shl = shl i32 %c, 4
%and = and i32 %shl, 268435440 ; 0x0ffffff0
%or = or i32 %and, 268435458 ; 0x10000002
ret i32 %or
}
;; Pattern 8: a = b | (c & shifted_mask)
;; Similar to pattern 7 but without shift to c.
define i32 @pat8(i32 %c) nounwind {
; CHECK-LABEL: pat8:
; CHECK: # %bb.0:
; CHECK-NEXT: srli.w $a1, $a0, 4
; CHECK-NEXT: lu12i.w $a0, 65536
; CHECK-NEXT: ori $a0, $a0, 2
; CHECK-NEXT: bstrins.w $a0, $a1, 27, 4
; CHECK-NEXT: ret
%and = and i32 %c, 268435440 ; 0x0ffffff0
%or = or i32 %and, 268435458 ; 0x10000002
ret i32 %or
}
;; Test that bstrins.w is not generated because constant OR operand
;; doesn't fit into bits cleared by constant AND operand.
define i32 @no_bstrins_w(i32 %a) nounwind {
; CHECK-LABEL: no_bstrins_w:
; CHECK: # %bb.0:
; CHECK-NEXT: lu12i.w $a1, 291
; CHECK-NEXT: ori $a1, $a1, 1104
; CHECK-NEXT: or $a0, $a0, $a1
; CHECK-NEXT: lu12i.w $a1, -3805
; CHECK-NEXT: ori $a1, $a1, 1279
; CHECK-NEXT: and $a0, $a0, $a1
; CHECK-NEXT: ret
%and = and i32 %a, 4278190335 ; 0xff0000ff
%or = or i32 %and, 1193040 ; 0x00123450
ret i32 %or
}