Compiler projects using llvm
; RUN: llc < %s -mtriple=ve | FileCheck %s

;;; Test ‘shl’ instruction
;;;
;;; Syntax:
;;;   <result> = shl <ty> <op1>, <op2>           ; yields ty:result
;;;   <result> = shl nuw <ty> <op1>, <op2>       ; yields ty:result
;;;   <result> = shl nsw <ty> <op1>, <op2>       ; yields ty:result
;;;   <result> = shl nuw nsw <ty> <op1>, <op2>   ; yields ty:result
;;;
;;; Overview:
;;;   The ‘shl’ instruction returns the first operand shifted to the left
;;;   a specified number of bits.
;;;
;;; Arguments:
;;;   Both arguments to the ‘shl’ instruction must be the same integer or
;;;   vector of integer type. ‘op2’ is treated as an unsigned value.
;;;
;;; Semantics:
;;;   The value produced is op1 * 2op2 mod 2n, where n is the width of the
;;;   result. If op2 is (statically or dynamically) equal to or larger than
;;;   the number of bits in op1, this instruction returns a poison value.
;;;   If the arguments are vectors, each vector element of op1 is shifted by
;;;   the corresponding shift amount in op2.
;;;
;;;   If the nuw keyword is present, then the shift produces a poison value
;;;   if it shifts out any non-zero bits. If the nsw keyword is present,
;;;   then the shift produces a poison value if it shifts out any bits that
;;;   disagree with the resultant sign bit.
;;;
;;; Example:
;;;   <result> = shl i32 4, %var   ; yields i32: 4 << %var
;;;   <result> = shl i32 4, 2      ; yields i32: 16
;;;   <result> = shl i32 1, 10     ; yields i32: 1024
;;;   <result> = shl i32 1, 32     ; undefined
;;;   <result> = shl <2 x i32> < i32 1, i32 1>, < i32 1, i32 2>
;;;                                ; yields: result=<2 x i32> < i32 2, i32 4>
;;;
;;; Note:
;;;   We test only i8/i16/i32/i64/i128 and unsigned of them.

; Function Attrs: norecurse nounwind readnone
define signext i8 @shl_i8_var(i8 signext %0, i8 signext %1) {
; CHECK-LABEL: shl_i8_var:
; CHECK:       # %bb.0:
; CHECK-NEXT:    and %s1, %s1, (56)0
; CHECK-NEXT:    sla.w.sx %s0, %s0, %s1
; CHECK-NEXT:    sll %s0, %s0, 56
; CHECK-NEXT:    sra.l %s0, %s0, 56
; CHECK-NEXT:    b.l.t (, %s10)
  %3 = sext i8 %0 to i32
  %4 = zext i8 %1 to i32
  %5 = shl i32 %3, %4
  %6 = trunc i32 %5 to i8
  ret i8 %6
}

; Function Attrs: norecurse nounwind readnone
define zeroext i8 @shl_u8_var(i8 zeroext %0, i8 zeroext %1) {
; CHECK-LABEL: shl_u8_var:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, %s0, %s1
; CHECK-NEXT:    and %s0, %s0, (56)0
; CHECK-NEXT:    b.l.t (, %s10)
  %3 = zext i8 %0 to i32
  %4 = zext i8 %1 to i32
  %5 = shl i32 %3, %4
  %6 = trunc i32 %5 to i8
  ret i8 %6
}

; Function Attrs: norecurse nounwind readnone
define signext i16 @shl_i16_var(i16 signext %0, i16 signext %1) {
; CHECK-LABEL: shl_i16_var:
; CHECK:       # %bb.0:
; CHECK-NEXT:    and %s1, %s1, (48)0
; CHECK-NEXT:    sla.w.sx %s0, %s0, %s1
; CHECK-NEXT:    sll %s0, %s0, 48
; CHECK-NEXT:    sra.l %s0, %s0, 48
; CHECK-NEXT:    b.l.t (, %s10)
  %3 = sext i16 %0 to i32
  %4 = zext i16 %1 to i32
  %5 = shl i32 %3, %4
  %6 = trunc i32 %5 to i16
  ret i16 %6
}

; Function Attrs: norecurse nounwind readnone
define zeroext i16 @shl_u16_var(i16 zeroext %0, i16 zeroext %1) {
; CHECK-LABEL: shl_u16_var:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, %s0, %s1
; CHECK-NEXT:    and %s0, %s0, (48)0
; CHECK-NEXT:    b.l.t (, %s10)
  %3 = zext i16 %0 to i32
  %4 = zext i16 %1 to i32
  %5 = shl i32 %3, %4
  %6 = trunc i32 %5 to i16
  ret i16 %6
}

; Function Attrs: norecurse nounwind readnone
define signext i32 @shl_i32_var(i32 signext %0, i32 signext %1) {
; CHECK-LABEL: shl_i32_var:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, %s0, %s1
; CHECK-NEXT:    adds.w.sx %s0, %s0, (0)1
; CHECK-NEXT:    b.l.t (, %s10)
  %3 = shl i32 %0, %1
  ret i32 %3
}

; Function Attrs: norecurse nounwind readnone
define zeroext i32 @shl_u32_var(i32 zeroext %0, i32 zeroext %1) {
; CHECK-LABEL: shl_u32_var:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, %s0, %s1
; CHECK-NEXT:    adds.w.zx %s0, %s0, (0)1
; CHECK-NEXT:    b.l.t (, %s10)
  %3 = shl i32 %0, %1
  ret i32 %3
}

; Function Attrs: norecurse nounwind readnone
define i64 @shl_i64_var(i64 %0, i64 %1) {
; CHECK-LABEL: shl_i64_var:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sll %s0, %s0, %s1
; CHECK-NEXT:    b.l.t (, %s10)
  %3 = shl i64 %0, %1
  ret i64 %3
}

; Function Attrs: norecurse nounwind readnone
define i64 @shl_u64_var(i64 %0, i64 %1) {
; CHECK-LABEL: shl_u64_var:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sll %s0, %s0, %s1
; CHECK-NEXT:    b.l.t (, %s10)
  %3 = shl i64 %0, %1
  ret i64 %3
}

; Function Attrs: norecurse nounwind readnone
define i128 @shl_i128_var(i128 %0, i128 %1) {
; CHECK-LABEL: shl_i128_var:
; CHECK:       .LBB{{[0-9]+}}_2:
; CHECK-NEXT:    and %s2, %s2, (32)0
; CHECK-NEXT:    lea %s3, __ashlti3@lo
; CHECK-NEXT:    and %s3, %s3, (32)0
; CHECK-NEXT:    lea.sl %s12, __ashlti3@hi(, %s3)
; CHECK-NEXT:    bsic %s10, (, %s12)
; CHECK-NEXT:    or %s11, 0, %s9
  %3 = shl i128 %0, %1
  ret i128 %3
}

; Function Attrs: norecurse nounwind readnone
define i128 @shl_u128_var(i128 %0, i128 %1) {
; CHECK-LABEL: shl_u128_var:
; CHECK:       .LBB{{[0-9]+}}_2:
; CHECK-NEXT:    and %s2, %s2, (32)0
; CHECK-NEXT:    lea %s3, __ashlti3@lo
; CHECK-NEXT:    and %s3, %s3, (32)0
; CHECK-NEXT:    lea.sl %s12, __ashlti3@hi(, %s3)
; CHECK-NEXT:    bsic %s10, (, %s12)
; CHECK-NEXT:    or %s11, 0, %s9
  %3 = shl i128 %0, %1
  ret i128 %3
}

; Function Attrs: norecurse nounwind readnone
define signext i8 @shl_const_i8(i8 signext %0) {
; CHECK-LABEL: shl_const_i8:
; CHECK:       # %bb.0:
; CHECK-NEXT:    and %s0, %s0, (56)0
; CHECK-NEXT:    sla.w.sx %s0, (62)1, %s0
; CHECK-NEXT:    sll %s0, %s0, 56
; CHECK-NEXT:    sra.l %s0, %s0, 56
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = zext i8 %0 to i32
  %3 = shl i32 -4, %2
  %4 = trunc i32 %3 to i8
  ret i8 %4
}

; Function Attrs: norecurse nounwind readnone
define zeroext i8 @shl_const_u8(i8 zeroext %0) {
; CHECK-LABEL: shl_const_u8:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, (62)1, %s0
; CHECK-NEXT:    lea %s1, 252
; CHECK-NEXT:    and %s0, %s0, %s1
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = zext i8 %0 to i32
  %3 = shl i32 -4, %2
  %4 = trunc i32 %3 to i8
  ret i8 %4
}

; Function Attrs: norecurse nounwind readnone
define signext i16 @shl_const_i16(i16 signext %0) {
; CHECK-LABEL: shl_const_i16:
; CHECK:       # %bb.0:
; CHECK-NEXT:    and %s0, %s0, (48)0
; CHECK-NEXT:    sla.w.sx %s0, (62)1, %s0
; CHECK-NEXT:    sll %s0, %s0, 48
; CHECK-NEXT:    sra.l %s0, %s0, 48
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = zext i16 %0 to i32
  %3 = shl i32 -4, %2
  %4 = trunc i32 %3 to i16
  ret i16 %4
}

; Function Attrs: norecurse nounwind readnone
define zeroext i16 @shl_const_u16(i16 zeroext %0) {
; CHECK-LABEL: shl_const_u16:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, (62)1, %s0
; CHECK-NEXT:    lea %s1, 65532
; CHECK-NEXT:    and %s0, %s0, %s1
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = zext i16 %0 to i32
  %3 = shl i32 -4, %2
  %4 = trunc i32 %3 to i16
  ret i16 %4
}

; Function Attrs: norecurse nounwind readnone
define signext i32 @shl_const_i32(i32 signext %0) {
; CHECK-LABEL: shl_const_i32:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, (62)1, %s0
; CHECK-NEXT:    adds.w.sx %s0, %s0, (0)1
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i32 -4, %0
  ret i32 %2
}

; Function Attrs: norecurse nounwind readnone
define zeroext i32 @shl_const_u32(i32 zeroext %0) {
; CHECK-LABEL: shl_const_u32:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, (62)1, %s0
; CHECK-NEXT:    adds.w.zx %s0, %s0, (0)1
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i32 -4, %0
  ret i32 %2
}

; Function Attrs: norecurse nounwind readnone
define i64 @shl_const_i64(i64 %0) {
; CHECK-LABEL: shl_const_i64:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sll %s0, (62)1, %s0
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i64 -4, %0
  ret i64 %2
}

; Function Attrs: norecurse nounwind readnone
define i64 @shl_const_u64(i64 %0) {
; CHECK-LABEL: shl_const_u64:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sll %s0, (62)1, %s0
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i64 -4, %0
  ret i64 %2
}

; Function Attrs: norecurse nounwind readnone
define i128 @shl_const_i128(i128 %0) {
; CHECK-LABEL: shl_const_i128:
; CHECK:       .LBB{{[0-9]+}}_2:
; CHECK-NEXT:    and %s2, %s0, (32)0
; CHECK-NEXT:    lea %s0, __ashlti3@lo
; CHECK-NEXT:    and %s0, %s0, (32)0
; CHECK-NEXT:    lea.sl %s12, __ashlti3@hi(, %s0)
; CHECK-NEXT:    or %s0, -4, (0)1
; CHECK-NEXT:    or %s1, -1, (0)1
; CHECK-NEXT:    bsic %s10, (, %s12)
; CHECK-NEXT:    or %s11, 0, %s9
  %2 = shl i128 -4, %0
  ret i128 %2
}

; Function Attrs: norecurse nounwind readnone
define i128 @shl_const_u128(i128 %0) {
; CHECK-LABEL: shl_const_u128:
; CHECK:       .LBB{{[0-9]+}}_2:
; CHECK-NEXT:    and %s2, %s0, (32)0
; CHECK-NEXT:    lea %s0, __ashlti3@lo
; CHECK-NEXT:    and %s0, %s0, (32)0
; CHECK-NEXT:    lea.sl %s12, __ashlti3@hi(, %s0)
; CHECK-NEXT:    or %s0, -4, (0)1
; CHECK-NEXT:    or %s1, -1, (0)1
; CHECK-NEXT:    bsic %s10, (, %s12)
; CHECK-NEXT:    or %s11, 0, %s9
  %2 = shl i128 -4, %0
  ret i128 %2
}

; Function Attrs: norecurse nounwind readnone
define signext i8 @shl_i8_const(i8 signext %0) {
; CHECK-LABEL: shl_i8_const:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, %s0, 3
; CHECK-NEXT:    sll %s0, %s0, 56
; CHECK-NEXT:    sra.l %s0, %s0, 56
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i8 %0, 3
  ret i8 %2
}

; Function Attrs: norecurse nounwind readnone
define zeroext i8 @shl_u8_const(i8 zeroext %0) {
; CHECK-LABEL: shl_u8_const:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, %s0, 3
; CHECK-NEXT:    lea %s1, 248
; CHECK-NEXT:    and %s0, %s0, %s1
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i8 %0, 3
  ret i8 %2
}

; Function Attrs: norecurse nounwind readnone
define signext i16 @shl_i16_const(i16 signext %0) {
; CHECK-LABEL: shl_i16_const:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, %s0, 7
; CHECK-NEXT:    sll %s0, %s0, 48
; CHECK-NEXT:    sra.l %s0, %s0, 48
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i16 %0, 7
  ret i16 %2
}

; Function Attrs: norecurse nounwind readnone
define zeroext i16 @shl_u16_const(i16 zeroext %0) {
; CHECK-LABEL: shl_u16_const:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, %s0, 7
; CHECK-NEXT:    lea %s1, 65408
; CHECK-NEXT:    and %s0, %s0, %s1
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i16 %0, 7
  ret i16 %2
}

; Function Attrs: norecurse nounwind readnone
define signext i32 @shl_i32_const(i32 signext %0) {
; CHECK-LABEL: shl_i32_const:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, %s0, 15
; CHECK-NEXT:    adds.w.sx %s0, %s0, (0)1
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i32 %0, 15
  ret i32 %2
}

; Function Attrs: norecurse nounwind readnone
define zeroext i32 @shl_u32_const(i32 zeroext %0) {
; CHECK-LABEL: shl_u32_const:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sla.w.sx %s0, %s0, 15
; CHECK-NEXT:    adds.w.zx %s0, %s0, (0)1
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i32 %0, 15
  ret i32 %2
}

; Function Attrs: norecurse nounwind readnone
define i64 @shl_i64_const(i64 %0) {
; CHECK-LABEL: shl_i64_const:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sll %s0, %s0, 63
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i64 %0, 63
  ret i64 %2
}

; Function Attrs: norecurse nounwind readnone
define i64 @shl_u64_const(i64 %0) {
; CHECK-LABEL: shl_u64_const:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sll %s0, %s0, 63
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i64 %0, 63
  ret i64 %2
}

; Function Attrs: norecurse nounwind readnone
define i128 @shl_i128_const(i128 %0) {
; CHECK-LABEL: shl_i128_const:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sll %s1, %s0, 63
; CHECK-NEXT:    or %s0, 0, (0)1
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i128 %0, 127
  ret i128 %2
}

; Function Attrs: norecurse nounwind readnone
define i128 @shl_u128_const(i128 %0) {
; CHECK-LABEL: shl_u128_const:
; CHECK:       # %bb.0:
; CHECK-NEXT:    sll %s1, %s0, 63
; CHECK-NEXT:    or %s0, 0, (0)1
; CHECK-NEXT:    b.l.t (, %s10)
  %2 = shl i128 %0, 127
  ret i128 %2
}