diff --git a/llvm/lib/Target/VE/VEISelLowering.cpp b/llvm/lib/Target/VE/VEISelLowering.cpp --- a/llvm/lib/Target/VE/VEISelLowering.cpp +++ b/llvm/lib/Target/VE/VEISelLowering.cpp @@ -556,13 +556,28 @@ 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 diff --git a/llvm/lib/Target/VE/VEInstrInfo.td b/llvm/lib/Target/VE/VEInstrInfo.td --- a/llvm/lib/Target/VE/VEInstrInfo.td +++ b/llvm/lib/Target/VE/VEInstrInfo.td @@ -533,6 +533,41 @@ } } +// Multiclass for RR type instructions with only 2 operands +// Used by pcnt, brv +let hasSideEffects = 0 in +multiclass RRI2mopc, 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 opc, @@ -760,6 +795,16 @@ } } +// 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 @@ (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)), diff --git a/llvm/test/CodeGen/VE/bitreverse.ll b/llvm/test/CodeGen/VE/bitreverse.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/VE/bitreverse.ll @@ -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 +} + diff --git a/llvm/test/CodeGen/VE/bswap.ll b/llvm/test/CodeGen/VE/bswap.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/VE/bswap.ll @@ -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 +} diff --git a/llvm/test/CodeGen/VE/ctlz.ll b/llvm/test/CodeGen/VE/ctlz.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/VE/ctlz.ll @@ -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) diff --git a/llvm/test/CodeGen/VE/ctpop.ll b/llvm/test/CodeGen/VE/ctpop.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/VE/ctpop.ll @@ -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) diff --git a/llvm/test/CodeGen/VE/cttz.ll b/llvm/test/CodeGen/VE/cttz.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/VE/cttz.ll @@ -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) diff --git a/llvm/test/CodeGen/VE/rotl.ll b/llvm/test/CodeGen/VE/rotl.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/VE/rotl.ll @@ -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 +} + diff --git a/llvm/test/CodeGen/VE/rotr.ll b/llvm/test/CodeGen/VE/rotr.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/VE/rotr.ll @@ -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 +}