[VE] Bit operator isel

Summary: Isel and tests for bswap,brev,ctpop,ctlz,ctty,rotl,rotr

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D74304
This commit is contained in:
Kazushi (Jam) Marukawa 2020-02-12 09:01:30 +01:00 committed by Simon Moll
parent 3662797ee9
commit 15a7384eb5
9 changed files with 490 additions and 2 deletions

View File

@ -556,13 +556,28 @@ VETargetLowering::VETargetLowering(const TargetMachine &TM,
setOperationAction(ISD::VAEND, MVT::Other, Expand);
/// } VAARG handling
// VE has no REM or DIVREM operations.
for (MVT IntVT : MVT::integer_valuetypes()) {
/// Int Ops {
for (MVT IntVT : {MVT::i32, MVT::i64}) {
// VE has no REM or DIVREM operations.
setOperationAction(ISD::UREM, IntVT, Expand);
setOperationAction(ISD::SREM, IntVT, Expand);
setOperationAction(ISD::SDIVREM, IntVT, Expand);
setOperationAction(ISD::UDIVREM, IntVT, Expand);
setOperationAction(ISD::CTTZ, IntVT, Expand);
setOperationAction(ISD::ROTL, IntVT, Expand);
setOperationAction(ISD::ROTR, IntVT, Expand);
// Use isel patterns for i32 and i64
setOperationAction(ISD::BSWAP, IntVT, Legal);
setOperationAction(ISD::CTLZ, IntVT, Legal);
setOperationAction(ISD::CTPOP, IntVT, Legal);
// Use isel patterns for i64, Promote i32
LegalizeAction Act = (IntVT == MVT::i32) ? Promote : Legal;
setOperationAction(ISD::BITREVERSE, IntVT, Act);
}
/// } Int Ops
/// Conversion {
// VE doesn't have instructions for fp<->uint, so expand them by llvm

View File

@ -533,6 +533,41 @@ multiclass RRCMOVm<string opcStr, bits<8>opc,
}
}
// Multiclass for RR type instructions with only 2 operands
// Used by pcnt, brv
let hasSideEffects = 0 in
multiclass RRI2m<string opcStr, bits<8>opc, RegisterClass RC, ValueType Ty,
Operand immOp2, SDPatternOperator OpNode=null_frag> {
def r : RR<
opc, (outs RC:$sx), (ins RC:$sz),
!strconcat(opcStr, " $sx, $sz"),
[(set Ty:$sx, (OpNode Ty:$sz))]> {
let cy = 1;
let cz = 1;
}
def i : RR<
opc, (outs RC:$sx), (ins RC:$sz),
!strconcat(opcStr, " $sx, $sz"),
[(set Ty:$sx, (OpNode Ty:$sz))]> {
let cy = 0;
let cz = 1;
}
def m0 : RR<
opc, (outs RC:$sx), (ins immOp2:$sz),
!strconcat(opcStr, " $sx, (${sz})0")> {
let cy = 1;
let cz = 0;
let sz{6} = 1;
}
def m1 : RR<
opc, (outs RC:$sx), (ins immOp2:$sz),
!strconcat(opcStr, " $sx, (${sz})1")> {
let cy = 1;
let cz = 0;
}
}
// Branch multiclass
let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 in
multiclass BCRm<string opcStr, string opcStrAt, bits<8> opc,
@ -760,6 +795,16 @@ let cx = 0 in {
}
}
// Bits operations
let cx = 0 in {
defm PCNT : RRI2m<"pcnt", 0x38, I64, i64, uimm6Op64, ctpop>;
defm BRV : RRI2m<"brv", 0x39, I64, i64, uimm6Op64, bitreverse>;
defm LDZ : RRI2m<"ldz", 0x67, I64, i64, uimm6Op64, ctlz>;
defm BSWP : RRIm<"bswp", 0x2B, I64, i64, simm7Op64, uimm6Op64>;
}
// 5.3.2.4 Shift Instructions
@ -1426,6 +1471,19 @@ def : Pat<(f32 (bitconvert i32:$op)),
(EXTRACT_SUBREG (SLLri (INSERT_SUBREG (i64 (IMPLICIT_DEF)),
$op, sub_i32), 32), sub_f32)>;
// Bits operations pattern matchings.
def : Pat<(i32 (ctpop i32:$src)),
(EXTRACT_SUBREG (PCNTr (ANDrm0 (INSERT_SUBREG
(i64 (IMPLICIT_DEF)), $src, sub_i32), 32)), sub_i32)>;
def : Pat<(i32 (ctlz i32:$src)),
(EXTRACT_SUBREG (LDZr (SLLri (INSERT_SUBREG
(i64 (IMPLICIT_DEF)), $src, sub_i32), 32)), sub_i32)>;
def : Pat<(i64 (bswap i64:$src)),
(BSWPri $src, 0)>;
def : Pat<(i32 (bswap i32:$src)),
(EXTRACT_SUBREG (BSWPri (INSERT_SUBREG
(i64 (IMPLICIT_DEF)), $src, sub_i32), 1), sub_i32)>;
// Several special pattern matches to optimize code
def : Pat<(i32 (and i32:$lhs, 0xff)),

View File

@ -0,0 +1,100 @@
; RUN: llc < %s -mtriple=ve-unknown-unknown | FileCheck %s
define i64 @func1(i64 %p) {
; CHECK-LABEL: func1:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: brv %s0, %s0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i64 @llvm.bitreverse.i64(i64 %p)
ret i64 %r
}
declare i64 @llvm.bitreverse.i64(i64)
define i32 @func2(i32 %p) {
; CHECK-LABEL: func2:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: brv %s0, %s0
; CHECK-NEXT: srl %s0, %s0, 32
; CHECK-NEXT: adds.w.sx %s0, %s0, (0)1
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i32 @llvm.bitreverse.i32(i32 %p)
ret i32 %r
}
declare i32 @llvm.bitreverse.i32(i32)
define signext i16 @func3(i16 signext %p) {
; CHECK-LABEL: func3:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: brv %s0, %s0
; CHECK-NEXT: sra.l %s0, %s0, 48
; CHECK-NEXT: adds.w.sx %s0, %s0, (0)1
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i16 @llvm.bitreverse.i16(i16 %p)
ret i16 %r
}
declare i16 @llvm.bitreverse.i16(i16)
define signext i8 @func4(i8 signext %p) {
; CHECK-LABEL: func4:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: brv %s0, %s0
; CHECK-NEXT: sra.l %s0, %s0, 56
; CHECK-NEXT: adds.w.sx %s0, %s0, (0)1
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i8 @llvm.bitreverse.i8(i8 %p)
ret i8 %r
}
declare i8 @llvm.bitreverse.i8(i8)
define i64 @func5(i64 %p) {
; CHECK-LABEL: func5:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: brv %s0, %s0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i64 @llvm.bitreverse.i64(i64 %p)
ret i64 %r
}
define i32 @func6(i32 %p) {
; CHECK-LABEL: func6:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: brv %s0, %s0
; CHECK-NEXT: srl %s0, %s0, 32
; CHECK-NEXT: adds.w.sx %s0, %s0, (0)1
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i32 @llvm.bitreverse.i32(i32 %p)
ret i32 %r
}
define zeroext i16 @func7(i16 zeroext %p) {
; CHECK-LABEL: func7:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: brv %s0, %s0
; CHECK-NEXT: srl %s0, %s0, 48
; CHECK-NEXT: adds.w.sx %s0, %s0, (0)1
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i16 @llvm.bitreverse.i16(i16 %p)
ret i16 %r
}
define zeroext i8 @func8(i8 zeroext %p) {
; CHECK-LABEL: func8:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: brv %s0, %s0
; CHECK-NEXT: srl %s0, %s0, 56
; CHECK-NEXT: adds.w.sx %s0, %s0, (0)1
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i8 @llvm.bitreverse.i8(i8 %p)
ret i8 %r
}

71
test/CodeGen/VE/bswap.ll Normal file
View File

@ -0,0 +1,71 @@
; RUN: llc < %s -mtriple=ve-unknown-unknown | FileCheck %s
define i64 @func1(i64 %p) {
; CHECK-LABEL: func1:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: bswp %s0, %s0, 0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i64 @llvm.bswap.i64(i64 %p)
ret i64 %r
}
declare i64 @llvm.bswap.i64(i64)
define i32 @func2(i32 %p) {
; CHECK-LABEL: func2:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: bswp %s0, %s0, 1
; CHECK-NEXT: # kill: def $sw0 killed $sw0 killed $sx0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i32 @llvm.bswap.i32(i32 %p)
ret i32 %r
}
declare i32 @llvm.bswap.i32(i32)
define signext i16 @func3(i16 signext %p) {
; CHECK-LABEL: func3:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: bswp %s0, %s0, 1
; CHECK-NEXT: sra.w.sx %s0, %s0, 16
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i16 @llvm.bswap.i16(i16 %p)
ret i16 %r
}
declare i16 @llvm.bswap.i16(i16)
define i64 @func4(i64 %p) {
; CHECK-LABEL: func4:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: bswp %s0, %s0, 0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i64 @llvm.bswap.i64(i64 %p)
ret i64 %r
}
define i32 @func5(i32 %p) {
; CHECK-LABEL: func5:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: bswp %s0, %s0, 1
; CHECK-NEXT: # kill: def $sw0 killed $sw0 killed $sx0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i32 @llvm.bswap.i32(i32 %p)
ret i32 %r
}
define zeroext i16 @func6(i16 zeroext %p) {
; CHECK-LABEL: func6:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: bswp %s0, %s0, 1
; CHECK-NEXT: and %s0, %s0, (32)0
; CHECK-NEXT: srl %s0, %s0, 16
; CHECK-NEXT: # kill: def $sw0 killed $sw0 killed $sx0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i16 @llvm.bswap.i16(i16 %p)
ret i16 %r
}

54
test/CodeGen/VE/ctlz.ll Normal file
View File

@ -0,0 +1,54 @@
; RUN: llc < %s -mtriple=ve-unknown-unknown | FileCheck %s
define i64 @func1(i64 %p) {
; CHECK-LABEL: func1:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: ldz %s0, %s0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i64 @llvm.ctlz.i64(i64 %p, i1 true)
ret i64 %r
}
declare i64 @llvm.ctlz.i64(i64, i1)
define i32 @func2(i32 %p) {
; CHECK-LABEL: func2:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: sll %s0, %s0, 32
; CHECK-NEXT: ldz %s0, %s0
; CHECK-NEXT: # kill: def $sw0 killed $sw0 killed $sx0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i32 @llvm.ctlz.i32(i32 %p, i1 true)
ret i32 %r
}
declare i32 @llvm.ctlz.i32(i32, i1)
define i16 @func3(i16 %p) {
; CHECK-LABEL: func3:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: and %s0, %s0, (48)0
; CHECK-NEXT: sll %s0, %s0, 32
; CHECK-NEXT: ldz %s0, %s0
; CHECK-NEXT: lea %s0, -16(%s0)
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i16 @llvm.ctlz.i16(i16 %p, i1 true)
ret i16 %r
}
declare i16 @llvm.ctlz.i16(i16, i1)
define i8 @func4(i8 %p) {
; CHECK-LABEL: func4:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: and %s0, %s0, (56)0
; CHECK-NEXT: sll %s0, %s0, 32
; CHECK-NEXT: ldz %s0, %s0
; CHECK-NEXT: lea %s0, -24(%s0)
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i8 @llvm.ctlz.i8(i8 %p, i1 true)
ret i8 %r
}
declare i8 @llvm.ctlz.i8(i8, i1)

54
test/CodeGen/VE/ctpop.ll Normal file
View File

@ -0,0 +1,54 @@
; RUN: llc < %s -mtriple=ve-unknown-unknown | FileCheck %s
define i64 @func1(i64 %p) {
; CHECK-LABEL: func1:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: pcnt %s0, %s0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i64 @llvm.ctpop.i64(i64 %p)
ret i64 %r
}
declare i64 @llvm.ctpop.i64(i64 %p)
define i32 @func2(i32 %p) {
; CHECK-LABEL: func2:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: and %s0, %s0, (32)0
; CHECK-NEXT: pcnt %s0, %s0
; CHECK-NEXT: # kill: def $sw0 killed $sw0 killed $sx0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i32 @llvm.ctpop.i32(i32 %p)
ret i32 %r
}
declare i32 @llvm.ctpop.i32(i32 %p)
define i16 @func3(i16 %p) {
; CHECK-LABEL: func3:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: and %s0, %s0, (48)0
; CHECK-NEXT: and %s0, %s0, (32)0
; CHECK-NEXT: pcnt %s0, %s0
; CHECK-NEXT: # kill: def $sw0 killed $sw0 killed $sx0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i16 @llvm.ctpop.i16(i16 %p)
ret i16 %r
}
declare i16 @llvm.ctpop.i16(i16 %p)
define i8 @func4(i8 %p) {
; CHECK-LABEL: func4:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: and %s0, %s0, (56)0
; CHECK-NEXT: and %s0, %s0, (32)0
; CHECK-NEXT: pcnt %s0, %s0
; CHECK-NEXT: # kill: def $sw0 killed $sw0 killed $sx0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i8 @llvm.ctpop.i8(i8 %p)
ret i8 %r
}
declare i8 @llvm.ctpop.i8(i8)

63
test/CodeGen/VE/cttz.ll Normal file
View File

@ -0,0 +1,63 @@
; RUN: llc < %s -mtriple=ve-unknown-unknown | FileCheck %s
define i64 @func1(i64 %p) {
; CHECK-LABEL: func1:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: lea %s1, -1(%s0)
; CHECK-NEXT: xor %s0, -1, %s0
; CHECK-NEXT: and %s0, %s0, %s1
; CHECK-NEXT: pcnt %s0, %s0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i64 @llvm.cttz.i64(i64 %p, i1 true)
ret i64 %r
}
declare i64 @llvm.cttz.i64(i64, i1)
define i32 @func2(i32 %p) {
; CHECK-LABEL: func2:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: lea %s1, -1(%s0)
; CHECK-NEXT: xor %s0, -1, %s0
; CHECK-NEXT: and %s0, %s0, %s1
; CHECK-NEXT: and %s0, %s0, (32)0
; CHECK-NEXT: pcnt %s0, %s0
; CHECK-NEXT: # kill: def $sw0 killed $sw0 killed $sx0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i32 @llvm.cttz.i32(i32 %p, i1 true)
ret i32 %r
}
declare i32 @llvm.cttz.i32(i32, i1)
define i16 @func3(i16 %p) {
; CHECK-LABEL: func3:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: lea %s1, -1(%s0)
; CHECK-NEXT: xor %s0, -1, %s0
; CHECK-NEXT: and %s0, %s0, %s1
; CHECK-NEXT: and %s0, %s0, (32)0
; CHECK-NEXT: pcnt %s0, %s0
; CHECK-NEXT: # kill: def $sw0 killed $sw0 killed $sx0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i16 @llvm.cttz.i16(i16 %p, i1 true)
ret i16 %r
}
declare i16 @llvm.cttz.i16(i16, i1)
define i8 @func4(i8 %p) {
; CHECK-LABEL: func4:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: lea %s1, -1(%s0)
; CHECK-NEXT: xor %s0, -1, %s0
; CHECK-NEXT: and %s0, %s0, %s1
; CHECK-NEXT: and %s0, %s0, (32)0
; CHECK-NEXT: pcnt %s0, %s0
; CHECK-NEXT: # kill: def $sw0 killed $sw0 killed $sx0
; CHECK-NEXT: or %s11, 0, %s9
%r = tail call i8 @llvm.cttz.i8(i8 %p, i1 true)
ret i8 %r
}
declare i8 @llvm.cttz.i8(i8, i1)

37
test/CodeGen/VE/rotl.ll Normal file
View File

@ -0,0 +1,37 @@
; RUN: llc < %s -mtriple=ve-unknown-unknown | FileCheck %s
define i64 @func1(i64 %a, i32 %b) {
; CHECK-LABEL: func1:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: sll %s2, %s0, %s1
; CHECK-NEXT: lea %s3, 64
; CHECK-NEXT: subs.w.sx %s1, %s3, %s1
; CHECK-NEXT: srl %s0, %s0, %s1
; CHECK-NEXT: or %s0, %s0, %s2
; CHECK-NEXT: or %s11, 0, %s9
%b64 = zext i32 %b to i64
%a.sl = shl i64 %a, %b64
%b.inv = sub nsw i32 64, %b
%b.inv64 = zext i32 %b.inv to i64
%a.sr = lshr i64 %a, %b.inv64
%r = or i64 %a.sr, %a.sl
ret i64 %r
}
define i32 @func2(i32 %a, i32 %b) {
; CHECK-LABEL: func2:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: sla.w.sx %s2, %s0, %s1
; CHECK-NEXT: subs.w.sx %s1, 32, %s1
; CHECK-NEXT: and %s0, %s0, (32)0
; CHECK-NEXT: srl %s0, %s0, %s1
; CHECK-NEXT: or %s0, %s0, %s2
; CHECK-NEXT: or %s11, 0, %s9
%a.sl = shl i32 %a, %b
%b.inv = sub nsw i32 32, %b
%a.sr = lshr i32 %a, %b.inv
%r = or i32 %a.sr, %a.sl
ret i32 %r
}

36
test/CodeGen/VE/rotr.ll Normal file
View File

@ -0,0 +1,36 @@
; RUN: llc < %s -mtriple=ve-unknown-unknown | FileCheck %s
define i64 @func1(i64 %a, i32 %b) {
; CHECK-LABEL: func1:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: srl %s2, %s0, %s1
; CHECK-NEXT: lea %s3, 64
; CHECK-NEXT: subs.w.sx %s1, %s3, %s1
; CHECK-NEXT: sll %s0, %s0, %s1
; CHECK-NEXT: or %s0, %s0, %s2
; CHECK-NEXT: or %s11, 0, %s9
%b64 = zext i32 %b to i64
%a.lr = lshr i64 %a, %b64
%b.inv = sub nsw i32 64, %b
%b.inv64 = zext i32 %b.inv to i64
%a.sl = shl i64 %a, %b.inv64
%r = or i64 %a.sl, %a.lr
ret i64 %r
}
define i32 @func2(i32 %a, i32 %b) {
; CHECK-LABEL: func2:
; CHECK: .LBB{{[0-9]+}}_2:
; CHECK-NEXT: # kill: def $sw0 killed $sw0 def $sx0
; CHECK-NEXT: and %s2, %s0, (32)0
; CHECK-NEXT: srl %s2, %s2, %s1
; CHECK-NEXT: subs.w.sx %s1, 32, %s1
; CHECK-NEXT: sla.w.sx %s0, %s0, %s1
; CHECK-NEXT: or %s0, %s0, %s2
; CHECK-NEXT: or %s11, 0, %s9
%a.lr = lshr i32 %a, %b
%b.inv = sub nsw i32 32, %b
%a.sl = shl i32 %a, %b.inv
%r = or i32 %a.sl, %a.lr
ret i32 %r
}