blob: e682309e1aa9dd7860459684e8ac47d22cc8f147 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s
; The reduced values are the zero-extended bytes of the same wider loaded
; scalar: the gather is emitted as a bitcast to the byte vector plus an
; extension.
define i16 @sum8_i64(ptr %x) {
; CHECK-LABEL: define i16 @sum8_i64(
; CHECK-SAME: ptr [[X:%.*]]) {
; CHECK-NEXT: [[START:.*:]]
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[X]], align 8
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i64 [[L]] to <8 x i8>
; CHECK-NEXT: [[TMP1:%.*]] = zext <8 x i8> [[TMP0]] to <8 x i16>
; CHECK-NEXT: [[TMP2:%.*]] = call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> [[TMP1]])
; CHECK-NEXT: ret i16 [[TMP2]]
;
start:
%l = load i64, ptr %x, align 8
%t0 = trunc i64 %l to i16
%b0 = and i16 %t0, 255
%t1 = trunc i64 %l to i16
%b1 = lshr i16 %t1, 8
%a1 = add nuw nsw i16 %b0, %b1
%s2 = lshr i64 %l, 16
%t2 = trunc i64 %s2 to i16
%b2 = and i16 %t2, 255
%a2 = add nuw nsw i16 %a1, %b2
%s3 = lshr i64 %l, 24
%t3 = trunc i64 %s3 to i16
%b3 = and i16 %t3, 255
%a3 = add nuw nsw i16 %a2, %b3
%s4 = lshr i64 %l, 32
%t4 = trunc i64 %s4 to i16
%b4 = and i16 %t4, 255
%a4 = add nuw nsw i16 %a3, %b4
%s5 = lshr i64 %l, 40
%t5 = trunc i64 %s5 to i16
%b5 = and i16 %t5, 255
%a5 = add nuw nsw i16 %a4, %b5
%s6 = lshr i64 %l, 48
%t6 = trunc i64 %s6 to i16
%b6 = and i16 %t6, 255
%a6 = add nuw nsw i16 %a5, %b6
%s7 = lshr i64 %l, 56
%b7 = trunc i64 %s7 to i16
%a7 = add nuw nsw i16 %a6, %b7
ret i16 %a7
}
; Same with ashr: the and-mask kills the sign bits, only the low byte is
; observed.
define i16 @sum8_i64_ashr(ptr %x) {
; CHECK-LABEL: define i16 @sum8_i64_ashr(
; CHECK-SAME: ptr [[X:%.*]]) {
; CHECK-NEXT: [[START:.*:]]
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[X]], align 8
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i64 [[L]] to <8 x i8>
; CHECK-NEXT: [[TMP1:%.*]] = zext <8 x i8> [[TMP0]] to <8 x i16>
; CHECK-NEXT: [[TMP2:%.*]] = call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> [[TMP1]])
; CHECK-NEXT: ret i16 [[TMP2]]
;
start:
%l = load i64, ptr %x, align 8
%t0 = trunc i64 %l to i16
%b0 = and i16 %t0, 255
%s1 = ashr i64 %l, 8
%t1 = trunc i64 %s1 to i16
%b1 = and i16 %t1, 255
%a1 = add nuw nsw i16 %b0, %b1
%s2 = ashr i64 %l, 16
%t2 = trunc i64 %s2 to i16
%b2 = and i16 %t2, 255
%a2 = add nuw nsw i16 %a1, %b2
%s3 = ashr i64 %l, 24
%t3 = trunc i64 %s3 to i16
%b3 = and i16 %t3, 255
%a3 = add nuw nsw i16 %a2, %b3
%s4 = ashr i64 %l, 32
%t4 = trunc i64 %s4 to i16
%b4 = and i16 %t4, 255
%a4 = add nuw nsw i16 %a3, %b4
%s5 = ashr i64 %l, 40
%t5 = trunc i64 %s5 to i16
%b5 = and i16 %t5, 255
%a5 = add nuw nsw i16 %a4, %b5
%s6 = ashr i64 %l, 48
%t6 = trunc i64 %s6 to i16
%b6 = and i16 %t6, 255
%a6 = add nuw nsw i16 %a5, %b6
%s7 = ashr i64 %l, 56
%t7 = trunc i64 %s7 to i16
%b7 = and i16 %t7, 255
%a7 = add nuw nsw i16 %a6, %b7
ret i16 %a7
}
; 16-bit sub-fields: matched and reduced as the field vector with the
; extension to the i32 lanes.
define i32 @sum4_halves_i64(ptr %p) {
; CHECK-LABEL: define i32 @sum4_halves_i64(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[START:.*:]]
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[P]], align 8
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i64 [[L]] to <4 x i16>
; CHECK-NEXT: [[TMP1:%.*]] = zext <4 x i16> [[TMP0]] to <4 x i32>
; CHECK-NEXT: [[A3:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[TMP1]])
; CHECK-NEXT: ret i32 [[A3]]
;
start:
%l = load i64, ptr %p, align 8
%t0 = trunc i64 %l to i32
%b0 = and i32 %t0, 65535
%s1 = lshr i64 %l, 16
%t1 = trunc i64 %s1 to i32
%b1 = and i32 %t1, 65535
%s2 = lshr i64 %l, 32
%t2 = trunc i64 %s2 to i32
%b2 = and i32 %t2, 65535
%s3 = lshr i64 %l, 48
%b3 = trunc i64 %s3 to i32
%a1 = add nuw nsw i32 %b0, %b1
%a2 = add nuw nsw i32 %a1, %b2
%a3 = add nuw nsw i32 %a2, %b3
ret i32 %a3
}
; Only 4 bytes of an i32: reduced as the field vector with the extension to
; the i16 lanes.
define i16 @sum4_i32(ptr %p) {
; CHECK-LABEL: define i16 @sum4_i32(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[START:.*:]]
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32 [[L]] to <4 x i8>
; CHECK-NEXT: [[TMP1:%.*]] = zext <4 x i8> [[TMP0]] to <4 x i16>
; CHECK-NEXT: [[A3:%.*]] = call i16 @llvm.vector.reduce.add.v4i16(<4 x i16> [[TMP1]])
; CHECK-NEXT: ret i16 [[A3]]
;
start:
%l = load i32, ptr %p, align 4
%t0 = trunc i32 %l to i16
%b0 = and i16 %t0, 255
%s1 = lshr i32 %l, 8
%t1 = trunc i32 %s1 to i16
%b1 = and i16 %t1, 255
%s2 = lshr i32 %l, 16
%t2 = trunc i32 %s2 to i16
%b2 = and i16 %t2, 255
%s3 = lshr i32 %l, 24
%b3 = trunc i32 %s3 to i16
%a1 = add nuw nsw i16 %b0, %b1
%a2 = add nuw nsw i16 %a1, %b2
%a3 = add nuw nsw i16 %a2, %b3
ret i16 %a3
}
; The same byte twice: the permutation is not a full one, the natural byte
; order cannot be used.
define i16 @sum4_i32_dup(ptr %p) {
; CHECK-LABEL: define i16 @sum4_i32_dup(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[START:.*:]]
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: [[T0A:%.*]] = trunc i32 [[L]] to i16
; CHECK-NEXT: [[B0A:%.*]] = and i16 [[T0A]], 255
; CHECK-NEXT: [[T0B:%.*]] = trunc i32 [[L]] to i8
; CHECK-NEXT: [[B0B:%.*]] = zext i8 [[T0B]] to i16
; CHECK-NEXT: [[S2:%.*]] = lshr i32 [[L]], 16
; CHECK-NEXT: [[T2:%.*]] = trunc i32 [[S2]] to i16
; CHECK-NEXT: [[B2:%.*]] = and i16 [[T2]], 255
; CHECK-NEXT: [[S3:%.*]] = lshr i32 [[L]], 24
; CHECK-NEXT: [[B3:%.*]] = trunc i32 [[S3]] to i16
; CHECK-NEXT: [[A1:%.*]] = add nuw nsw i16 [[B0A]], [[B0B]]
; CHECK-NEXT: [[A2:%.*]] = add nuw nsw i16 [[A1]], [[B2]]
; CHECK-NEXT: [[A3:%.*]] = add nuw nsw i16 [[A2]], [[B3]]
; CHECK-NEXT: ret i16 [[A3]]
;
start:
%l = load i32, ptr %p, align 4
%t0a = trunc i32 %l to i16
%b0a = and i16 %t0a, 255
%t0b = trunc i32 %l to i8
%b0b = zext i8 %t0b to i16
%s2 = lshr i32 %l, 16
%t2 = trunc i32 %s2 to i16
%b2 = and i16 %t2, 255
%s3 = lshr i32 %l, 24
%b3 = trunc i32 %s3 to i16
%a1 = add nuw nsw i16 %b0a, %b0b
%a2 = add nuw nsw i16 %a1, %b2
%a3 = add nuw nsw i16 %a2, %b3
ret i16 %a3
}
; Bytes stored to memory: the lane order is observable, the byte vector is
; permuted.
define void @store_bytes_i64(ptr %p, ptr %out) {
; CHECK-LABEL: define void @store_bytes_i64(
; CHECK-SAME: ptr [[P:%.*]], ptr [[OUT:%.*]]) {
; CHECK-NEXT: [[START:.*:]]
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[P]], align 8
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i64 [[L]] to <8 x i8>
; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <8 x i8> [[TMP0]], <8 x i8> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
; CHECK-NEXT: [[TMP2:%.*]] = zext <4 x i8> [[TMP1]] to <4 x i16>
; CHECK-NEXT: store <4 x i16> [[TMP2]], ptr [[OUT]], align 2
; CHECK-NEXT: ret void
;
start:
%l = load i64, ptr %p, align 8
%t0 = trunc i64 %l to i16
%b0 = and i16 %t0, 255
%t1 = trunc i64 %l to i16
%b1 = lshr i16 %t1, 8
%s2 = lshr i64 %l, 16
%t2 = trunc i64 %s2 to i16
%b2 = and i16 %t2, 255
%s3 = lshr i64 %l, 24
%t3 = trunc i64 %s3 to i16
%b3 = and i16 %t3, 255
store i16 %b0, ptr %out, align 2
%o1 = getelementptr i16, ptr %out, i64 1
store i16 %b1, ptr %o1, align 2
%o2 = getelementptr i16, ptr %out, i64 2
store i16 %b2, ptr %o2, align 2
%o3 = getelementptr i16, ptr %out, i64 3
store i16 %b3, ptr %o3, align 2
ret void
}
; 16-bit sub-fields stored to memory.
define void @store_halves_i64(ptr %p, ptr %out) {
; CHECK-LABEL: define void @store_halves_i64(
; CHECK-SAME: ptr [[P:%.*]], ptr [[OUT:%.*]]) {
; CHECK-NEXT: [[START:.*:]]
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[P]], align 8
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i64 [[L]] to <4 x i16>
; CHECK-NEXT: [[TMP1:%.*]] = zext <4 x i16> [[TMP0]] to <4 x i32>
; CHECK-NEXT: store <4 x i32> [[TMP1]], ptr [[OUT]], align 4
; CHECK-NEXT: ret void
;
start:
%l = load i64, ptr %p, align 8
%t0 = trunc i64 %l to i32
%b0 = and i32 %t0, 65535
%s1 = lshr i64 %l, 16
%t1 = trunc i64 %s1 to i32
%b1 = and i32 %t1, 65535
%s2 = lshr i64 %l, 32
%t2 = trunc i64 %s2 to i32
%b2 = and i32 %t2, 65535
%s3 = lshr i64 %l, 48
%b3 = trunc i64 %s3 to i32
store i32 %b0, ptr %out, align 4
%o1 = getelementptr i32, ptr %out, i64 1
store i32 %b1, ptr %o1, align 4
%o2 = getelementptr i32, ptr %out, i64 2
store i32 %b2, ptr %o2, align 4
%o3 = getelementptr i32, ptr %out, i64 3
store i32 %b3, ptr %o3, align 4
ret void
}
; Not sub-fields: the 16-bit values sit at misaligned offsets.
define i16 @misaligned_fields_i64(ptr %p) {
; CHECK-LABEL: define i16 @misaligned_fields_i64(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[START:.*:]]
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[P]], align 8
; CHECK-NEXT: [[W0:%.*]] = trunc i64 [[L]] to i16
; CHECK-NEXT: [[S1:%.*]] = lshr i64 [[L]], 8
; CHECK-NEXT: [[W1:%.*]] = trunc i64 [[S1]] to i16
; CHECK-NEXT: [[A:%.*]] = add i16 [[W0]], [[W1]]
; CHECK-NEXT: ret i16 [[A]]
;
start:
%l = load i64, ptr %p, align 8
%w0 = trunc i64 %l to i16
%s1 = lshr i64 %l, 8
%w1 = trunc i64 %s1 to i16
%a = add i16 %w0, %w1
ret i16 %a
}
; Same fields as in sum8_i64, but reduced in a scrambled order: the lane
; order of the reduction root is unobservable, the fields are emitted in the
; natural order and no permutation is needed.
define i16 @sum8_i64_scrambled(ptr %x) {
; CHECK-LABEL: define i16 @sum8_i64_scrambled(
; CHECK-SAME: ptr [[X:%.*]]) {
; CHECK-NEXT: [[START:.*:]]
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[X]], align 8
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i64 [[L]] to <8 x i8>
; CHECK-NEXT: [[TMP1:%.*]] = zext <8 x i8> [[TMP0]] to <8 x i16>
; CHECK-NEXT: [[TMP2:%.*]] = call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> [[TMP1]])
; CHECK-NEXT: ret i16 [[TMP2]]
;
start:
%l = load i64, ptr %x, align 8
%t0 = trunc i64 %l to i16
%b0 = and i16 %t0, 255
%s1 = lshr i64 %l, 8
%t1 = trunc i64 %s1 to i16
%b1 = and i16 %t1, 255
%s2 = lshr i64 %l, 16
%t2 = trunc i64 %s2 to i16
%b2 = and i16 %t2, 255
%s3 = lshr i64 %l, 24
%t3 = trunc i64 %s3 to i16
%b3 = and i16 %t3, 255
%s4 = lshr i64 %l, 32
%t4 = trunc i64 %s4 to i16
%b4 = and i16 %t4, 255
%s5 = lshr i64 %l, 40
%t5 = trunc i64 %s5 to i16
%b5 = and i16 %t5, 255
%s6 = lshr i64 %l, 48
%t6 = trunc i64 %s6 to i16
%b6 = and i16 %t6, 255
%s7 = lshr i64 %l, 56
%b7 = trunc i64 %s7 to i16
%a1 = add nuw nsw i16 %b3, %b0
%a2 = add nuw nsw i16 %a1, %b5
%a3 = add nuw nsw i16 %a2, %b1
%a4 = add nuw nsw i16 %a3, %b7
%a5 = add nuw nsw i16 %a4, %b2
%a6 = add nuw nsw i16 %a5, %b6
%a7 = add nuw nsw i16 %a6, %b4
ret i16 %a7
}
; A gathered field with an external use stays as a scalar; the lane order of
; the reduction root gather is still unobservable, so the permutation is
; elided.
define i16 @sum8_i64_ext_use(ptr %p, ptr %out) {
; CHECK-LABEL: define i16 @sum8_i64_ext_use(
; CHECK-SAME: ptr [[P:%.*]], ptr [[OUT:%.*]]) {
; CHECK-NEXT: [[START:.*:]]
; CHECK-NEXT: [[L:%.*]] = load i64, ptr [[P]], align 8
; CHECK-NEXT: [[S3:%.*]] = lshr i64 [[L]], 24
; CHECK-NEXT: [[T6:%.*]] = trunc i64 [[S3]] to i16
; CHECK-NEXT: [[B6:%.*]] = and i16 [[T6]], 255
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i64 [[L]] to <8 x i8>
; CHECK-NEXT: [[TMP1:%.*]] = zext <8 x i8> [[TMP0]] to <8 x i16>
; CHECK-NEXT: [[TMP2:%.*]] = call i16 @llvm.vector.reduce.add.v8i16(<8 x i16> [[TMP1]])
; CHECK-NEXT: store i16 [[B6]], ptr [[OUT]], align 2
; CHECK-NEXT: ret i16 [[TMP2]]
;
start:
%l = load i64, ptr %p, align 8
%t0 = trunc i64 %l to i16
%b0 = and i16 %t0, 255
%t1 = trunc i64 %l to i16
%b1 = lshr i16 %t1, 8
%s2 = lshr i64 %l, 16
%t2 = trunc i64 %s2 to i16
%b2 = and i16 %t2, 255
%s3 = lshr i64 %l, 24
%t3 = trunc i64 %s3 to i16
%b3 = and i16 %t3, 255
%s4 = lshr i64 %l, 32
%t4 = trunc i64 %s4 to i16
%b4 = and i16 %t4, 255
%s5 = lshr i64 %l, 40
%t5 = trunc i64 %s5 to i16
%b5 = and i16 %t5, 255
%s6 = lshr i64 %l, 48
%t6 = trunc i64 %s6 to i16
%b6 = and i16 %t6, 255
%s7 = lshr i64 %l, 56
%b7 = trunc i64 %s7 to i16
%a1 = add nuw nsw i16 %b0, %b1
%a2 = add nuw nsw i16 %a1, %b2
%a3 = add nuw nsw i16 %a2, %b3
%a4 = add nuw nsw i16 %a3, %b4
%a5 = add nuw nsw i16 %a4, %b5
%a6 = add nuw nsw i16 %a5, %b6
%a7 = add nuw nsw i16 %a6, %b7
store i16 %b3, ptr %out, align 2
ret i16 %a7
}
define void @vectorized_src(ptr %p, ptr %a, i64 %x) {
; CHECK-LABEL: define void @vectorized_src(
; CHECK-SAME: ptr [[P:%.*]], ptr [[A:%.*]], i64 [[X:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i64>, ptr [[P]], align 8
; CHECK-NEXT: [[LD1:%.*]] = load i64, ptr [[GEP]], align 8
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[LD1]] to <2 x i32>
; CHECK-NEXT: [[TMP2:%.*]] = sitofp <2 x i32> [[TMP1]] to <2 x double>
; CHECK-NEXT: [[TMP3:%.*]] = trunc <2 x i64> [[TMP0]] to <2 x i32>
; CHECK-NEXT: [[TMP4:%.*]] = trunc i64 [[X]] to i32
; CHECK-NEXT: [[TMP5:%.*]] = insertelement <2 x i32> [[TMP3]], i32 [[TMP4]], i64 1
; CHECK-NEXT: [[TMP6:%.*]] = sitofp <2 x i32> [[TMP5]] to <2 x double>
; CHECK-NEXT: [[TMP7:%.*]] = fsub <2 x double> [[TMP2]], [[TMP6]]
; CHECK-NEXT: store <2 x double> [[TMP7]], ptr [[A]], align 8
; CHECK-NEXT: ret void
;
entry:
%ld0 = load i64, ptr %p, align 8
%gep = getelementptr inbounds nuw i8, ptr %p, i64 8
%ld1 = load i64, ptr %gep, align 8
%t0 = trunc i64 %ld1 to i32
%c0 = sitofp i32 %t0 to double
%t1 = trunc i64 %ld0 to i32
%c1 = sitofp i32 %t1 to double
%sub0 = fsub double %c0, %c1
store double %sub0, ptr %a, align 8
%s = lshr i64 %ld1, 32
%t2 = trunc nuw i64 %s to i32
%c2 = sitofp i32 %t2 to double
%t3 = trunc i64 %x to i32
%c3 = sitofp i32 %t3 to double
%sub1 = fsub double %c2, %c3
%gep.a = getelementptr inbounds nuw i8, ptr %a, i64 8
store double %sub1, ptr %gep.a, align 8
ret void
}
; A byte reused in the add reduction: the fields of the reduction root are
; emitted in the natural order, the repeat count scales the lane of that byte.
define i32 @sum4_i32_reused(i32 %x) {
; CHECK-LABEL: define i32 @sum4_i32_reused(
; CHECK-SAME: i32 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32 [[X]] to <4 x i8>
; CHECK-NEXT: [[TMP2:%.*]] = zext <4 x i8> [[TMP1]] to <4 x i16>
; CHECK-NEXT: [[TMP3:%.*]] = zext <4 x i16> [[TMP2]] to <4 x i32>
; CHECK-NEXT: [[TMP4:%.*]] = mul <4 x i32> [[TMP3]], <i32 1, i32 1, i32 1, i32 3>
; CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[TMP4]])
; CHECK-NEXT: ret i32 [[TMP5]]
;
%t0 = trunc i32 %x to i8
%s1 = lshr i32 %x, 8
%t1 = trunc i32 %s1 to i8
%s2 = lshr i32 %x, 16
%t2 = trunc i32 %s2 to i8
%s3 = lshr i32 %x, 24
%t3 = trunc i32 %s3 to i8
%f0 = zext i8 %t0 to i32
%f1 = zext i8 %t1 to i32
%f2 = zext i8 %t2 to i32
%f3 = zext i8 %t3 to i32
%a = add i32 %f2, %f0
%b = add i32 %a, %f3
%c = add i32 %b, %f1
%d = add i32 %c, %f3
%e = add i32 %d, %f3
ret i32 %e
}
; A byte reused twice in the xor reduction cancels out: the lane of that byte
; is zeroed in the natural order of the fields of the reduction root.
define i16 @xor8_i64_reused(i64 %x) {
; CHECK-LABEL: define i16 @xor8_i64_reused(
; CHECK-SAME: i64 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[X]] to <8 x i8>
; CHECK-NEXT: [[TMP2:%.*]] = zext <8 x i8> [[TMP1]] to <8 x i16>
; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <8 x i16> [[TMP2]], <8 x i16> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 8>
; CHECK-NEXT: [[TMP4:%.*]] = call i16 @llvm.vector.reduce.xor.v8i16(<8 x i16> [[TMP3]])
; CHECK-NEXT: ret i16 [[TMP4]]
;
%t0 = trunc i64 %x to i8
%f0 = zext i8 %t0 to i16
%s1 = lshr i64 %x, 8
%t1 = trunc i64 %s1 to i8
%f1 = zext i8 %t1 to i16
%s2 = lshr i64 %x, 16
%t2 = trunc i64 %s2 to i8
%f2 = zext i8 %t2 to i16
%s3 = lshr i64 %x, 24
%t3 = trunc i64 %s3 to i8
%f3 = zext i8 %t3 to i16
%s4 = lshr i64 %x, 32
%t4 = trunc i64 %s4 to i8
%f4 = zext i8 %t4 to i16
%s5 = lshr i64 %x, 40
%t5 = trunc i64 %s5 to i8
%f5 = zext i8 %t5 to i16
%s6 = lshr i64 %x, 48
%t6 = trunc i64 %s6 to i8
%f6 = zext i8 %t6 to i16
%s7 = lshr i64 %x, 56
%t7 = trunc i64 %s7 to i8
%f7 = zext i8 %t7 to i16
%r0 = xor i16 %f5, %f2
%r1 = xor i16 %r0, %f7
%r2 = xor i16 %r1, %f0
%r3 = xor i16 %r2, %f3
%r4 = xor i16 %r3, %f6
%r5 = xor i16 %r4, %f1
%r6 = xor i16 %r5, %f4
%r7 = xor i16 %r6, %f7
ret i16 %r7
}