CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
1797 lines
50 KiB
LLVM
1797 lines
50 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
|
; RUN: llc -mtriple=riscv64 -mattr=+experimental-p,+zbb,+m -verify-machineinstrs \
|
|
; RUN: < %s | FileCheck %s
|
|
|
|
define i32 @abs_i32(i32 %x) {
|
|
; CHECK-LABEL: abs_i32:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: absw a0, a0
|
|
; CHECK-NEXT: ret
|
|
%abs = tail call i32 @llvm.abs.i32(i32 %x, i1 true)
|
|
ret i32 %abs
|
|
}
|
|
|
|
define signext i32 @abs_i32_sext(i32 signext %x) {
|
|
; CHECK-LABEL: abs_i32_sext:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: absw a0, a0
|
|
; CHECK-NEXT: ret
|
|
%abs = tail call i32 @llvm.abs.i32(i32 %x, i1 true)
|
|
ret i32 %abs
|
|
}
|
|
|
|
define i64 @abs_i64(i64 %x) {
|
|
; CHECK-LABEL: abs_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: abs a0, a0
|
|
; CHECK-NEXT: ret
|
|
%abs = tail call i64 @llvm.abs.i64(i64 %x, i1 true)
|
|
ret i64 %abs
|
|
}
|
|
|
|
; Test scalar saturating add/sub operations for i32
|
|
define i32 @test_scalar_psadd_w(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: test_scalar_psadd_w:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: psadd.w a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%res = call i32 @llvm.sadd.sat.i32(i32 %a, i32 %b)
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @test_scalar_psaddu_w(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: test_scalar_psaddu_w:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: psaddu.w a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%res = call i32 @llvm.uadd.sat.i32(i32 %a, i32 %b)
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @test_scalar_pssub_w(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: test_scalar_pssub_w:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pssub.w a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%res = call i32 @llvm.ssub.sat.i32(i32 %a, i32 %b)
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @test_scalar_pssubu_w(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: test_scalar_pssubu_w:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pssubu.w a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%res = call i32 @llvm.usub.sat.i32(i32 %a, i32 %b)
|
|
ret i32 %res
|
|
}
|
|
|
|
define i64 @pack_i64_imm() {
|
|
; CHECK-LABEL: pack_i64_imm:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: lui a0, 16432
|
|
; CHECK-NEXT: addi a0, a0, 513
|
|
; CHECK-NEXT: pack a0, a0, a0
|
|
; CHECK-NEXT: ret
|
|
ret i64 u0x0403020104030201
|
|
}
|
|
|
|
; Make sure we prefer li over pli
|
|
define i64 @li_imm() {
|
|
; CHECK-LABEL: li_imm:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: li a0, -1
|
|
; CHECK-NEXT: ret
|
|
ret i64 -1
|
|
}
|
|
|
|
define i32 @pli_b_i32() {
|
|
; CHECK-LABEL: pli_b_i32:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: lui a0, 20560
|
|
; CHECK-NEXT: addi a0, a0, 1285
|
|
; CHECK-NEXT: ret
|
|
ret i32 u0x05050505
|
|
}
|
|
|
|
define i64 @pli_b_i64() {
|
|
; CHECK-LABEL: pli_b_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pli.b a0, -128
|
|
; CHECK-NEXT: ret
|
|
ret i64 u0x8080808080808080
|
|
}
|
|
|
|
define i32 @pli_h_i32() {
|
|
; CHECK-LABEL: pli_h_i32:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: lui a0, 1047840
|
|
; CHECK-NEXT: addi a0, a0, -47
|
|
; CHECK-NEXT: ret
|
|
ret i32 u0xffd1ffd1
|
|
}
|
|
|
|
define i64 @pli_h_i64() {
|
|
; CHECK-LABEL: pli_h_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pli.h a0, 291
|
|
; CHECK-NEXT: ret
|
|
ret i64 u0x0123012301230123
|
|
}
|
|
|
|
define i64 @pli_h_slli_i64() {
|
|
; CHECK-LABEL: pli_h_slli_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pli.h a0, 511
|
|
; CHECK-NEXT: slli a0, a0, 3
|
|
; CHECK-NEXT: ret
|
|
ret i64 u0x0ff80ff80ff80ff8
|
|
}
|
|
|
|
define i64 @pli_h_srli_i64() {
|
|
; CHECK-LABEL: pli_h_srli_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pli.h a0, -240
|
|
; CHECK-NEXT: srli a0, a0, 4
|
|
; CHECK-NEXT: ret
|
|
ret i64 u0x0ff10ff10ff10ff1
|
|
}
|
|
|
|
define i64 @pli_w_i64() {
|
|
; CHECK-LABEL: pli_w_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pli.w a0, -292
|
|
; CHECK-NEXT: ret
|
|
ret i64 u0xfffffedcfffffedc
|
|
}
|
|
|
|
define i64 @pli_w_slli_i64() {
|
|
; CHECK-LABEL: pli_w_slli_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pli.w a0, 511
|
|
; CHECK-NEXT: slli a0, a0, 7
|
|
; CHECK-NEXT: ret
|
|
ret i64 u0x0000ff800000ff80
|
|
}
|
|
|
|
define i64 @pli_w_srli_i64() {
|
|
; CHECK-LABEL: pli_w_srli_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pli.w a0, -480
|
|
; CHECK-NEXT: srli a0, a0, 5
|
|
; CHECK-NEXT: ret
|
|
ret i64 u0x07fffff107fffff1
|
|
}
|
|
|
|
define void @pli_b_store_i32(ptr %p) {
|
|
; CHECK-LABEL: pli_b_store_i32:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pli.b a1, 65
|
|
; CHECK-NEXT: sw a1, 0(a0)
|
|
; CHECK-NEXT: ret
|
|
store i32 u0x41414141, ptr %p
|
|
ret void
|
|
}
|
|
|
|
define void @pli_b_store_i16(ptr %p) {
|
|
; CHECK-LABEL: pli_b_store_i16:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pli.b a1, -127
|
|
; CHECK-NEXT: sh a1, 0(a0)
|
|
; CHECK-NEXT: ret
|
|
store i16 u0x8181, ptr %p
|
|
ret void
|
|
}
|
|
|
|
define i64 @plui_h_i64() {
|
|
; CHECK-LABEL: plui_h_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: plui.h a0, -9
|
|
; CHECK-NEXT: ret
|
|
ret i64 u0xfdc0fdc0fdc0fdc0
|
|
}
|
|
|
|
define void @plui_h_i32(ptr %p) {
|
|
; CHECK-LABEL: plui_h_i32:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: plui.h a1, -9
|
|
; CHECK-NEXT: sw a1, 0(a0)
|
|
; CHECK-NEXT: ret
|
|
store i32 u0xfdc0fdc0, ptr %p
|
|
ret void
|
|
}
|
|
|
|
; Make sure we use lui instead of plui.h.
|
|
define void @lui_i32(ptr %p) {
|
|
; CHECK-LABEL: lui_i32:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: lui a1, 524296
|
|
; CHECK-NEXT: sw a1, 0(a0)
|
|
; CHECK-NEXT: ret
|
|
store i32 u0x80008000, ptr %p
|
|
ret void
|
|
}
|
|
|
|
define i64 @plui_w_i64() {
|
|
; CHECK-LABEL: plui_w_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: plui.w a0, 473
|
|
; CHECK-NEXT: ret
|
|
ret i64 u0x7640000076400000
|
|
}
|
|
|
|
define i64 @pack_i64(i64 %a, i64 %b) nounwind {
|
|
; CHECK-LABEL: pack_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pack a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%shl = and i64 %a, 4294967295
|
|
%shl1 = shl i64 %b, 32
|
|
%or = or i64 %shl1, %shl
|
|
ret i64 %or
|
|
}
|
|
|
|
define i64 @pack_i64_2(i32 signext %a, i32 signext %b) nounwind {
|
|
; CHECK-LABEL: pack_i64_2:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pack a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%zexta = zext i32 %a to i64
|
|
%zextb = zext i32 %b to i64
|
|
%shl1 = shl i64 %zextb, 32
|
|
%or = or i64 %shl1, %zexta
|
|
ret i64 %or
|
|
}
|
|
|
|
define i64 @pack_i64_3(ptr %0, ptr %1) {
|
|
; CHECK-LABEL: pack_i64_3:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: lw a0, 0(a0)
|
|
; CHECK-NEXT: lw a1, 0(a1)
|
|
; CHECK-NEXT: pack a0, a1, a0
|
|
; CHECK-NEXT: ret
|
|
%3 = load i32, ptr %0, align 4
|
|
%4 = zext i32 %3 to i64
|
|
%5 = shl i64 %4, 32
|
|
%6 = load i32, ptr %1, align 4
|
|
%7 = zext i32 %6 to i64
|
|
%8 = or i64 %5, %7
|
|
ret i64 %8
|
|
}
|
|
|
|
define i8 @cls_i8(i8 %x) {
|
|
; CHECK-LABEL: cls_i8:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: sext.b a0, a0
|
|
; CHECK-NEXT: cls a0, a0
|
|
; CHECK-NEXT: addi a0, a0, -56
|
|
; CHECK-NEXT: ret
|
|
%a = ashr i8 %x, 7
|
|
%b = xor i8 %x, %a
|
|
%c = call i8 @llvm.ctlz.i8(i8 %b, i1 false)
|
|
%d = sub i8 %c, 1
|
|
ret i8 %d
|
|
}
|
|
|
|
define i8 @cls_i8_2(i8 %x) {
|
|
; CHECK-LABEL: cls_i8_2:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: sext.b a0, a0
|
|
; CHECK-NEXT: cls a0, a0
|
|
; CHECK-NEXT: addi a0, a0, -56
|
|
; CHECK-NEXT: ret
|
|
%a = ashr i8 %x, 7
|
|
%b = xor i8 %x, %a
|
|
%c = shl i8 %b, 1
|
|
%d = or i8 %c, 1
|
|
%e = call i8 @llvm.ctlz.i8(i8 %d, i1 true)
|
|
ret i8 %e
|
|
}
|
|
|
|
define i16 @cls_i16(i16 %x) {
|
|
; CHECK-LABEL: cls_i16:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: sext.h a0, a0
|
|
; CHECK-NEXT: cls a0, a0
|
|
; CHECK-NEXT: addi a0, a0, -48
|
|
; CHECK-NEXT: ret
|
|
%a = ashr i16 %x, 15
|
|
%b = xor i16 %x, %a
|
|
%c = call i16 @llvm.ctlz.i16(i16 %b, i1 false)
|
|
%d = sub i16 %c, 1
|
|
ret i16 %d
|
|
}
|
|
|
|
define i16 @cls_i16_2(i16 %x) {
|
|
; CHECK-LABEL: cls_i16_2:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: sext.h a0, a0
|
|
; CHECK-NEXT: cls a0, a0
|
|
; CHECK-NEXT: addi a0, a0, -48
|
|
; CHECK-NEXT: ret
|
|
%a = ashr i16 %x, 15
|
|
%b = xor i16 %x, %a
|
|
%c = shl i16 %b, 1
|
|
%d = or i16 %c, 1
|
|
%e = call i16 @llvm.ctlz.i16(i16 %d, i1 true)
|
|
ret i16 %e
|
|
}
|
|
|
|
define i32 @cls_i32(i32 %x) {
|
|
; CHECK-LABEL: cls_i32:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: clsw a0, a0
|
|
; CHECK-NEXT: ret
|
|
%a = ashr i32 %x, 31
|
|
%b = xor i32 %x, %a
|
|
%c = call i32 @llvm.ctlz.i32(i32 %b, i1 false)
|
|
%d = sub i32 %c, 1
|
|
ret i32 %d
|
|
}
|
|
|
|
define i32 @cls_i32_2(i32 %x) {
|
|
; CHECK-LABEL: cls_i32_2:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: clsw a0, a0
|
|
; CHECK-NEXT: ret
|
|
%a = ashr i32 %x, 31
|
|
%b = xor i32 %x, %a
|
|
%c = shl i32 %b, 1
|
|
%d = or i32 %c, 1
|
|
%e = call i32 @llvm.ctlz.i32(i32 %d, i1 true)
|
|
ret i32 %e
|
|
}
|
|
|
|
; The result is in the range [1-31], so we don't need an andi after the cls.
|
|
define i32 @cls_i32_knownbits(i32 %x) {
|
|
; CHECK-LABEL: cls_i32_knownbits:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: clsw a0, a0
|
|
; CHECK-NEXT: ret
|
|
%a = ashr i32 %x, 31
|
|
%b = xor i32 %x, %a
|
|
%c = call i32 @llvm.ctlz.i32(i32 %b, i1 false)
|
|
%d = sub i32 %c, 1
|
|
%e = and i32 %d, 31
|
|
ret i32 %e
|
|
}
|
|
|
|
; There are at least 16 redundant sign bits so we don't need an ori after the clsw.
|
|
define i32 @cls_i32_knownbits_2(i16 signext %x) {
|
|
; CHECK-LABEL: cls_i32_knownbits_2:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: clsw a0, a0
|
|
; CHECK-NEXT: ret
|
|
%sext = sext i16 %x to i32
|
|
%a = ashr i32 %sext, 31
|
|
%b = xor i32 %sext, %a
|
|
%c = call i32 @llvm.ctlz.i32(i32 %b, i1 false)
|
|
%d = sub i32 %c, 1
|
|
%e = or i32 %d, 16
|
|
ret i32 %e
|
|
}
|
|
|
|
; There are at least 24 redundant sign bits so we don't need an ori after the clsw.
|
|
define i32 @cls_i32_knownbits_3(i8 signext %x) {
|
|
; CHECK-LABEL: cls_i32_knownbits_3:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: clsw a0, a0
|
|
; CHECK-NEXT: ret
|
|
%sext = sext i8 %x to i32
|
|
%a = ashr i32 %sext, 31
|
|
%b = xor i32 %sext, %a
|
|
%c = call i32 @llvm.ctlz.i32(i32 %b, i1 false)
|
|
%d = sub i32 %c, 1
|
|
%e = or i32 %d, 24
|
|
ret i32 %e
|
|
}
|
|
|
|
; Negative test. We only know there is at least 1 redundant sign bit. We can't
|
|
; remove the ori.
|
|
define i32 @cls_i32_knownbits_4(i32 signext %x) {
|
|
; CHECK-LABEL: cls_i32_knownbits_4:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: slli a0, a0, 33
|
|
; CHECK-NEXT: srai a0, a0, 33
|
|
; CHECK-NEXT: clsw a0, a0
|
|
; CHECK-NEXT: ori a0, a0, 1
|
|
; CHECK-NEXT: ret
|
|
%shl = shl i32 %x, 1
|
|
%ashr = ashr i32 %shl, 1
|
|
%a = ashr i32 %ashr, 31
|
|
%b = xor i32 %ashr, %a
|
|
%c = call i32 @llvm.ctlz.i32(i32 %b, i1 false)
|
|
%d = sub i32 %c, 1
|
|
%e = or i32 %d, 1
|
|
ret i32 %e
|
|
}
|
|
|
|
define i64 @cls_i64(i64 %x) {
|
|
; CHECK-LABEL: cls_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: cls a0, a0
|
|
; CHECK-NEXT: ret
|
|
%a = ashr i64 %x, 63
|
|
%b = xor i64 %x, %a
|
|
%c = call i64 @llvm.ctlz.i64(i64 %b, i1 false)
|
|
%d = sub i64 %c, 1
|
|
ret i64 %d
|
|
}
|
|
|
|
define i64 @cls_i64_2(i64 %x) {
|
|
; CHECK-LABEL: cls_i64_2:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: cls a0, a0
|
|
; CHECK-NEXT: ret
|
|
%a = ashr i64 %x, 63
|
|
%b = xor i64 %x, %a
|
|
%c = shl i64 %b, 1
|
|
%d = or i64 %c, 1
|
|
%e = call i64 @llvm.ctlz.i64(i64 %d, i1 true)
|
|
ret i64 %e
|
|
}
|
|
|
|
; Check that the range max in ctls cls knownbits
|
|
; is not set to 32
|
|
define i64 @cls_i64_not_32(i64 %x) {
|
|
; CHECK-LABEL: cls_i64_not_32:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: srai a0, a0, 16
|
|
; CHECK-NEXT: cls a0, a0
|
|
; CHECK-NEXT: ori a0, a0, 16
|
|
; CHECK-NEXT: ret
|
|
%val = ashr i64 %x, 16
|
|
%a = ashr i64 %val, 63
|
|
%b = xor i64 %val, %a
|
|
%c = shl i64 %b, 1
|
|
%d = or i64 %c, 1
|
|
%e = call i64 @llvm.ctlz.i64(i64 %d, i1 true)
|
|
%f = or i64 %e, 16
|
|
ret i64 %f
|
|
}
|
|
|
|
define i128 @sll_i128(i128 %x, i128 %y) {
|
|
; CHECK-LABEL: sll_i128:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: sll a3, a0, a2
|
|
; CHECK-NEXT: slx a1, a0, a2
|
|
; CHECK-NEXT: slli a2, a2, 57
|
|
; CHECK-NEXT: srai a2, a2, 63
|
|
; CHECK-NEXT: mvm a1, a3, a2
|
|
; CHECK-NEXT: andn a0, a3, a2
|
|
; CHECK-NEXT: ret
|
|
%b = shl i128 %x, %y
|
|
ret i128 %b
|
|
}
|
|
|
|
define i128 @sll_small_i128(i128 %x, i128 %y) {
|
|
; CHECK-LABEL: sll_small_i128:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: sll a3, a0, a2
|
|
; CHECK-NEXT: slx a1, a0, a2
|
|
; CHECK-NEXT: mv a0, a3
|
|
; CHECK-NEXT: ret
|
|
%a = and i128 %y, 63
|
|
%b = shl i128 %x, %a
|
|
ret i128 %b
|
|
}
|
|
|
|
define i128 @sll_large_i128(i128 %x, i128 %y) {
|
|
; CHECK-LABEL: sll_large_i128:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: sll a1, a0, a2
|
|
; CHECK-NEXT: li a0, 0
|
|
; CHECK-NEXT: ret
|
|
%a = or i128 %y, 64
|
|
%b = shl i128 %x, %a
|
|
ret i128 %b
|
|
}
|
|
|
|
define i128 @slli_i128(i128 %x) {
|
|
; CHECK-LABEL: slli_i128:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: li a2, 49
|
|
; CHECK-NEXT: slx a1, a0, a2
|
|
; CHECK-NEXT: slli a0, a0, 49
|
|
; CHECK-NEXT: ret
|
|
%a = shl i128 %x, 49
|
|
ret i128 %a
|
|
}
|
|
|
|
define i128 @slli_i128_large(i128 %x) {
|
|
; CHECK-LABEL: slli_i128_large:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: slli a1, a0, 7
|
|
; CHECK-NEXT: li a0, 0
|
|
; CHECK-NEXT: ret
|
|
%a = shl i128 %x, 71
|
|
ret i128 %a
|
|
}
|
|
|
|
define i128 @srl_i128(i128 %x, i128 %y) {
|
|
; CHECK-LABEL: srl_i128:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: srl a3, a1, a2
|
|
; CHECK-NEXT: srx a0, a1, a2
|
|
; CHECK-NEXT: slli a2, a2, 57
|
|
; CHECK-NEXT: srai a2, a2, 63
|
|
; CHECK-NEXT: mvm a0, a3, a2
|
|
; CHECK-NEXT: andn a1, a3, a2
|
|
; CHECK-NEXT: ret
|
|
%b = lshr i128 %x, %y
|
|
ret i128 %b
|
|
}
|
|
|
|
define i128 @srl_small_i128(i128 %x, i128 %y) {
|
|
; CHECK-LABEL: srl_small_i128:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: srl a3, a1, a2
|
|
; CHECK-NEXT: srx a0, a1, a2
|
|
; CHECK-NEXT: mv a1, a3
|
|
; CHECK-NEXT: ret
|
|
%a = and i128 %y, 63
|
|
%b = lshr i128 %x, %a
|
|
ret i128 %b
|
|
}
|
|
|
|
define i128 @srl_large_i128(i128 %x, i128 %y) {
|
|
; CHECK-LABEL: srl_large_i128:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: srl a0, a1, a2
|
|
; CHECK-NEXT: li a1, 0
|
|
; CHECK-NEXT: ret
|
|
%a = or i128 %y, 64
|
|
%b = lshr i128 %x, %a
|
|
ret i128 %b
|
|
}
|
|
|
|
define i128 @srli_i128(i128 %x) {
|
|
; CHECK-LABEL: srli_i128:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: li a2, 49
|
|
; CHECK-NEXT: srx a0, a1, a2
|
|
; CHECK-NEXT: srli a1, a1, 49
|
|
; CHECK-NEXT: ret
|
|
%a = lshr i128 %x, 49
|
|
ret i128 %a
|
|
}
|
|
|
|
define i128 @srli_i128_large(i128 %x) {
|
|
; CHECK-LABEL: srli_i128_large:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: srli a0, a1, 7
|
|
; CHECK-NEXT: li a1, 0
|
|
; CHECK-NEXT: ret
|
|
%a = lshr i128 %x, 71
|
|
ret i128 %a
|
|
}
|
|
|
|
define i128 @sra_i128(i128 %x, i128 %y) {
|
|
; CHECK-LABEL: sra_i128:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: sra a3, a1, a2
|
|
; CHECK-NEXT: srx a0, a1, a2
|
|
; CHECK-NEXT: slli a2, a2, 57
|
|
; CHECK-NEXT: srai a2, a2, 63
|
|
; CHECK-NEXT: mvm a0, a3, a2
|
|
; CHECK-NEXT: sra a1, a3, a2
|
|
; CHECK-NEXT: ret
|
|
%b = ashr i128 %x, %y
|
|
ret i128 %b
|
|
}
|
|
|
|
define i128 @sra_small_i128(i128 %x, i128 %y) {
|
|
; CHECK-LABEL: sra_small_i128:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: sra a3, a1, a2
|
|
; CHECK-NEXT: srx a0, a1, a2
|
|
; CHECK-NEXT: mv a1, a3
|
|
; CHECK-NEXT: ret
|
|
%a = and i128 %y, 63
|
|
%b = ashr i128 %x, %a
|
|
ret i128 %b
|
|
}
|
|
|
|
define i128 @sra_large_i128(i128 %x, i128 %y) {
|
|
; CHECK-LABEL: sra_large_i128:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: sra a0, a1, a2
|
|
; CHECK-NEXT: srai a1, a1, 63
|
|
; CHECK-NEXT: ret
|
|
%a = or i128 %y, 64
|
|
%b = ashr i128 %x, %a
|
|
ret i128 %b
|
|
}
|
|
|
|
define i128 @srai_i128(i128 %x) {
|
|
; CHECK-LABEL: srai_i128:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: li a2, 49
|
|
; CHECK-NEXT: srx a0, a1, a2
|
|
; CHECK-NEXT: srai a1, a1, 49
|
|
; CHECK-NEXT: ret
|
|
%a = ashr i128 %x, 49
|
|
ret i128 %a
|
|
}
|
|
|
|
define i128 @srai_i128_large(i128 %x) {
|
|
; CHECK-LABEL: srai_i128_large:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: srai a0, a1, 7
|
|
; CHECK-NEXT: srai a1, a1, 63
|
|
; CHECK-NEXT: ret
|
|
%a = ashr i128 %x, 71
|
|
ret i128 %a
|
|
}
|
|
|
|
define i64 @slx_i64(i64 %a, i64 %b, i64 %shamt) {
|
|
; CHECK-LABEL: slx_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: slx a0, a1, a2
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call i64 @llvm.fshl.i64(i64 %a, i64 %b, i64 %shamt)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @slxi_i64(i64 %a, i64 %b) {
|
|
; CHECK-LABEL: slxi_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: li a2, 25
|
|
; CHECK-NEXT: slx a0, a1, a2
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call i64 @llvm.fshl.i64(i64 %a, i64 %b, i64 25)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @srx_i64(i64 %a, i64 %b, i64 %shamt) {
|
|
; CHECK-LABEL: srx_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: srx a1, a0, a2
|
|
; CHECK-NEXT: mv a0, a1
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call i64 @llvm.fshr.i64(i64 %a, i64 %b, i64 %shamt)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @srxi_i64(i64 %a, i64 %b) {
|
|
; CHECK-LABEL: srxi_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: li a2, 25
|
|
; CHECK-NEXT: srx a1, a0, a2
|
|
; CHECK-NEXT: mv a0, a1
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call i64 @llvm.fshr.i64(i64 %a, i64 %b, i64 25)
|
|
ret i64 %1
|
|
}
|
|
|
|
; Test bitwise merge: (mask & b) | (~mask & a)
|
|
define i64 @merge_i64(i64 %mask, i64 %a, i64 %b) nounwind {
|
|
; CHECK-LABEL: merge_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: merge a0, a1, a2
|
|
; CHECK-NEXT: ret
|
|
%and1 = and i64 %mask, %b
|
|
%not = xor i64 %mask, -1
|
|
%and2 = and i64 %not, %a
|
|
%or = or i64 %and1, %and2
|
|
ret i64 %or
|
|
}
|
|
|
|
; Test MERGE with swapped a/b arguments
|
|
define i64 @merge_i64_2(i64 %mask, i64 %b, i64 %a) nounwind {
|
|
; CHECK-LABEL: merge_i64_2:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: merge a0, a2, a1
|
|
; CHECK-NEXT: ret
|
|
%and1 = and i64 %mask, %b
|
|
%not = xor i64 %mask, -1
|
|
%and2 = and i64 %not, %a
|
|
%or = or i64 %and1, %and2
|
|
ret i64 %or
|
|
}
|
|
|
|
; Test MVM: result overwrites rs1 (%a)
|
|
define i64 @mvm_i64(i64 %a, i64 %mask, i64 %b) nounwind {
|
|
; CHECK-LABEL: mvm_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mvm a0, a2, a1
|
|
; CHECK-NEXT: ret
|
|
%and1 = and i64 %mask, %b
|
|
%not = xor i64 %mask, -1
|
|
%and2 = and i64 %not, %a
|
|
%or = or i64 %and1, %and2
|
|
ret i64 %or
|
|
}
|
|
|
|
; Test MVM with mask as last argument
|
|
define i64 @mvm_i64_2(i64 %a, i64 %b, i64 %mask) nounwind {
|
|
; CHECK-LABEL: mvm_i64_2:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mvm a0, a1, a2
|
|
; CHECK-NEXT: ret
|
|
%and1 = and i64 %mask, %b
|
|
%not = xor i64 %mask, -1
|
|
%and2 = and i64 %not, %a
|
|
%or = or i64 %and1, %and2
|
|
ret i64 %or
|
|
}
|
|
|
|
; Test MVMN: result overwrites rs2 (%b)
|
|
define i64 @mvmn_i64(i64 %b, i64 %mask, i64 %a) nounwind {
|
|
; CHECK-LABEL: mvmn_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mvmn a0, a2, a1
|
|
; CHECK-NEXT: ret
|
|
%and1 = and i64 %mask, %b
|
|
%not = xor i64 %mask, -1
|
|
%and2 = and i64 %not, %a
|
|
%or = or i64 %and1, %and2
|
|
ret i64 %or
|
|
}
|
|
|
|
; Test MVMN with mask as last argument
|
|
define i64 @mvmn_i64_2(i64 %b, i64 %a, i64 %mask) nounwind {
|
|
; CHECK-LABEL: mvmn_i64_2:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mvmn a0, a1, a2
|
|
; CHECK-NEXT: ret
|
|
%and1 = and i64 %mask, %b
|
|
%not = xor i64 %mask, -1
|
|
%and2 = and i64 %not, %a
|
|
%or = or i64 %and1, %and2
|
|
ret i64 %or
|
|
}
|
|
|
|
; Test case where none of the source operands can be overwritten,
|
|
; requiring a mv before merge
|
|
define i64 @merge_i64_mv(i64 %mask, i64 %a, i64 %b) nounwind {
|
|
; CHECK-LABEL: merge_i64_mv:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mv a3, a0
|
|
; CHECK-NEXT: merge a3, a1, a2
|
|
; CHECK-NEXT: add a0, a0, a1
|
|
; CHECK-NEXT: add a0, a3, a0
|
|
; CHECK-NEXT: add a0, a0, a2
|
|
; CHECK-NEXT: ret
|
|
%and1 = and i64 %mask, %b
|
|
%not = xor i64 %mask, -1
|
|
%and2 = and i64 %not, %a
|
|
%or = or i64 %and1, %and2
|
|
%sum1 = add i64 %or, %mask
|
|
%sum2 = add i64 %sum1, %a
|
|
%sum3 = add i64 %sum2, %b
|
|
ret i64 %sum3
|
|
}
|
|
|
|
; Test alternate merge pattern: (a ^ b) & mask ^ a
|
|
define i64 @merge_xor_i64(i64 %mask, i64 %a, i64 %b) nounwind {
|
|
; CHECK-LABEL: merge_xor_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: merge a0, a1, a2
|
|
; CHECK-NEXT: ret
|
|
%xor1 = xor i64 %a, %b
|
|
%and = and i64 %xor1, %mask
|
|
%xor2 = xor i64 %and, %a
|
|
ret i64 %xor2
|
|
}
|
|
|
|
; Test alternate merge pattern with different argument order for MVM
|
|
define i64 @mvm_xor_i64(i64 %a, i64 %mask, i64 %b) nounwind {
|
|
; CHECK-LABEL: mvm_xor_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mvm a0, a2, a1
|
|
; CHECK-NEXT: ret
|
|
%xor1 = xor i64 %a, %b
|
|
%and = and i64 %xor1, %mask
|
|
%xor2 = xor i64 %and, %a
|
|
ret i64 %xor2
|
|
}
|
|
|
|
; Test alternate merge pattern with different argument order for MVMN
|
|
define i64 @mvmn_xor_i64(i64 %b, i64 %mask, i64 %a) nounwind {
|
|
; CHECK-LABEL: mvmn_xor_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mvmn a0, a2, a1
|
|
; CHECK-NEXT: ret
|
|
%xor1 = xor i64 %a, %b
|
|
%and = and i64 %xor1, %mask
|
|
%xor2 = xor i64 %and, %a
|
|
ret i64 %xor2
|
|
}
|
|
|
|
define signext i32 @mm_sati_8_i32(i32 signext %x) {
|
|
; CHECK-LABEL: mm_sati_8_i32:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: sati a0, a0, 8
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i32 @llvm.smin.i32(i32 %x, i32 127)
|
|
%1 = call i32 @llvm.smax.i32(i32 %0, i32 -128)
|
|
ret i32 %1
|
|
}
|
|
|
|
define signext i32 @mm_sati_16_i32(i32 signext %x) {
|
|
; CHECK-LABEL: mm_sati_16_i32:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: sati a0, a0, 16
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i32 @llvm.smax.i32(i32 %x, i32 -32768)
|
|
%1 = call i32 @llvm.smin.i32(i32 %0, i32 32767)
|
|
ret i32 %1
|
|
}
|
|
|
|
define signext i32 @mm_sati_24_i32(i32 signext %x) {
|
|
; CHECK-LABEL: mm_sati_24_i32:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: sati a0, a0, 24
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i32 @llvm.smin.i32(i32 %x, i32 8388607)
|
|
%1 = call i32 @llvm.smax.i32(i32 %0, i32 -8388608)
|
|
ret i32 %1
|
|
}
|
|
|
|
define signext i32 @mm_sati_32_i32(i32 signext %x) {
|
|
; CHECK-LABEL: mm_sati_32_i32:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i32 @llvm.smax.i32(i32 %x, i32 -2147483648)
|
|
%1 = call i32 @llvm.smin.i32(i32 %0, i32 2147483647)
|
|
ret i32 %1
|
|
}
|
|
|
|
define signext i32 @mm_sati_1_i32(i32 signext %x) {
|
|
; CHECK-LABEL: mm_sati_1_i32:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: sati a0, a0, 1
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i32 @llvm.smin.i32(i32 %x, i32 0)
|
|
%1 = call i32 @llvm.smax.i32(i32 %0, i32 -1)
|
|
ret i32 %1
|
|
}
|
|
|
|
define signext i32 @mm_sati_minallones_i32(i32 signext %x) {
|
|
; CHECK-LABEL: mm_sati_minallones_i32:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: li a0, 0
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i32 @llvm.smin.i32(i32 %x, i32 -1)
|
|
%1 = call i32 @llvm.smax.i32(i32 %0, i32 0)
|
|
ret i32 %1
|
|
}
|
|
|
|
define signext i32 @mm_sati_minallones2_i32(i32 signext %x) {
|
|
; CHECK-LABEL: mm_sati_minallones2_i32:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: li a0, -1
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i32 @llvm.smax.i32(i32 %x, i32 0)
|
|
%1 = call i32 @llvm.smin.i32(i32 %0, i32 -1)
|
|
ret i32 %1
|
|
}
|
|
|
|
define signext i32 @mm_usati_8_i32(i32 signext %x) {
|
|
; CHECK-LABEL: mm_usati_8_i32:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: usati a0, a0, 8
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i32 @llvm.smin.i32(i32 %x, i32 255)
|
|
%1 = call i32 @llvm.smax.i32(i32 %0, i32 0)
|
|
ret i32 %1
|
|
}
|
|
|
|
define signext i32 @mm_usati_16_i32(i32 signext %x) {
|
|
; CHECK-LABEL: mm_usati_16_i32:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: usati a0, a0, 16
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i32 @llvm.smax.i32(i32 %x, i32 0)
|
|
%1 = call i32 @llvm.smin.i32(i32 %0, i32 65535)
|
|
ret i32 %1
|
|
}
|
|
|
|
define signext i32 @mm_usati_1_i32(i32 signext %x) {
|
|
; CHECK-LABEL: mm_usati_1_i32:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: usati a0, a0, 1
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i32 @llvm.smax.i32(i32 %x, i32 0)
|
|
%1 = call i32 @llvm.smin.i32(i32 %0, i32 1)
|
|
ret i32 %1
|
|
}
|
|
|
|
define signext i32 @mm_usati_31_i32(i32 signext %x) {
|
|
; CHECK-LABEL: mm_usati_31_i32:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: max a0, a0, zero
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i32 @llvm.smin.i32(i32 %x, i32 2147483647)
|
|
%1 = call i32 @llvm.smax.i32(i32 %0, i32 0)
|
|
ret i32 %1
|
|
}
|
|
|
|
define signext i32 @mm_usati_32_i32(i32 signext %x) {
|
|
; CHECK-LABEL: mm_usati_32_i32:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: li a0, -1
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i32 @llvm.smax.i32(i32 %x, i32 0)
|
|
%1 = call i32 @llvm.smin.i32(i32 %0, i32 4294967295)
|
|
ret i32 %1
|
|
}
|
|
|
|
define i64 @mm_sati_8_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_sati_8_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: sati a0, a0, 8
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smin.i64(i64 %x, i64 127)
|
|
%1 = call i64 @llvm.smax.i64(i64 %0, i64 -128)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @mm_sati_16_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_sati_16_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: sati a0, a0, 16
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smax.i64(i64 %x, i64 -32768)
|
|
%1 = call i64 @llvm.smin.i64(i64 %0, i64 32767)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @mm_sati_24_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_sati_24_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: sati a0, a0, 24
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smin.i64(i64 %x, i64 8388607)
|
|
%1 = call i64 @llvm.smax.i64(i64 %0, i64 -8388608)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @mm_sati_32_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_sati_32_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: sati a0, a0, 32
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smax.i64(i64 %x, i64 -2147483648)
|
|
%1 = call i64 @llvm.smin.i64(i64 %0, i64 2147483647)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @mm_sati_1_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_sati_1_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: sati a0, a0, 1
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smin.i64(i64 %x, i64 0)
|
|
%1 = call i64 @llvm.smax.i64(i64 %0, i64 -1)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @mm_sati_minallones_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_sati_minallones_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: li a0, 0
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smin.i64(i64 %x, i64 -1)
|
|
%1 = call i64 @llvm.smax.i64(i64 %0, i64 0)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @mm_sati_minallones2_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_sati_minallones2_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: li a0, -1
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smax.i64(i64 %x, i64 0)
|
|
%1 = call i64 @llvm.smin.i64(i64 %0, i64 -1)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @mm_usati_8_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_usati_8_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: usati a0, a0, 8
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smin.i64(i64 %x, i64 255)
|
|
%1 = call i64 @llvm.smax.i64(i64 %0, i64 0)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @mm_usati_16_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_usati_16_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: usati a0, a0, 16
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smax.i64(i64 %x, i64 0)
|
|
%1 = call i64 @llvm.smin.i64(i64 %0, i64 65535)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @mm_usati_1_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_usati_1_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: usati a0, a0, 1
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smax.i64(i64 %x, i64 0)
|
|
%1 = call i64 @llvm.smin.i64(i64 %0, i64 1)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @mm_usati_31_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_usati_31_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: usati a0, a0, 31
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smin.i64(i64 %x, i64 2147483647)
|
|
%1 = call i64 @llvm.smax.i64(i64 %0, i64 0)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @mm_usati_32_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_usati_32_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: usati a0, a0, 32
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smax.i64(i64 %x, i64 0)
|
|
%1 = call i64 @llvm.smin.i64(i64 %0, i64 4294967295)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @mm_usati_55_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_usati_55_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: usati a0, a0, 55
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smax.i64(i64 %x, i64 0)
|
|
%1 = call i64 @llvm.smin.i64(i64 %0, i64 u0x7FFFFFFFFFFFFF)
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @mm_usati_64_i64(i64 %x) {
|
|
; CHECK-LABEL: mm_usati_64_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: li a0, -1
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smax.i64(i64 %x, i64 0)
|
|
%1 = call i64 @llvm.smin.i64(i64 %0, i64 -1)
|
|
ret i64 %1
|
|
}
|
|
|
|
; Test that we select remw.
|
|
define signext i32 @mm_sati_32_numsignbits_i64(i64 %x, i32 %y) {
|
|
; CHECK-LABEL: mm_sati_32_numsignbits_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: sati a0, a0, 32
|
|
; CHECK-NEXT: remw a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smax.i64(i64 %x, i64 -2147483648)
|
|
%1 = call i64 @llvm.smin.i64(i64 %0, i64 2147483647)
|
|
%2 = sext i32 %y to i64
|
|
%3 = srem i64 %1, %2
|
|
%4 = trunc i64 %3 to i32
|
|
ret i32 %4
|
|
}
|
|
|
|
; Test multiply patterns with one extended operand
|
|
define i64 @mul_w00_sexti32_sext_inreg(i32 signext %a, i64 %b) nounwind {
|
|
; CHECK-LABEL: mul_w00_sexti32_sext_inreg:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mul.w00 a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%a_sext = sext i32 %a to i64
|
|
%b_trunc = trunc i64 %b to i32
|
|
%b_sext = sext i32 %b_trunc to i64
|
|
%mul = mul i64 %a_sext, %b_sext
|
|
ret i64 %mul
|
|
}
|
|
|
|
define i64 @mul_w00_sexti32_sext_inreg_commute(i32 signext %a, i64 %b) nounwind {
|
|
; CHECK-LABEL: mul_w00_sexti32_sext_inreg_commute:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mul.w00 a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%a_sext = sext i32 %a to i64
|
|
%b_trunc = trunc i64 %b to i32
|
|
%b_sext = sext i32 %b_trunc to i64
|
|
%mul = mul i64 %b_sext, %a_sext
|
|
ret i64 %mul
|
|
}
|
|
|
|
define i64 @mulu_w00_zexti32_and(i32 zeroext %a, i64 %b) nounwind {
|
|
; CHECK-LABEL: mulu_w00_zexti32_and:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mulu.w00 a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%a_zext = zext i32 %a to i64
|
|
%b_and = and i64 %b, 4294967295
|
|
%mul = mul i64 %a_zext, %b_and
|
|
ret i64 %mul
|
|
}
|
|
|
|
define i64 @mulu_w00_zexti32_and_commute(i32 zeroext %a, i64 %b) nounwind {
|
|
; CHECK-LABEL: mulu_w00_zexti32_and_commute:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mulu.w00 a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%a_zext = zext i32 %a to i64
|
|
%b_and = and i64 %b, 4294967295
|
|
%mul = mul i64 %b_and, %a_zext
|
|
ret i64 %mul
|
|
}
|
|
|
|
define i64 @mulsu_w00_sexti32_and(i32 signext %a, i64 %b) nounwind {
|
|
; CHECK-LABEL: mulsu_w00_sexti32_and:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mulsu.w00 a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%a_sext = sext i32 %a to i64
|
|
%b_and = and i64 %b, 4294967295
|
|
%mul = mul i64 %a_sext, %b_and
|
|
ret i64 %mul
|
|
}
|
|
|
|
define i64 @mulsu_w00_sexti32_and_commute(i32 signext %a, i64 %b) nounwind {
|
|
; CHECK-LABEL: mulsu_w00_sexti32_and_commute:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mulsu.w00 a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%a_sext = sext i32 %a to i64
|
|
%b_and = and i64 %b, 4294967295
|
|
%mul = mul i64 %b_and, %a_sext
|
|
ret i64 %mul
|
|
}
|
|
|
|
define i64 @mulsu_w00_sext_inreg_zexti32(i64 %a, i32 zeroext %b) nounwind {
|
|
; CHECK-LABEL: mulsu_w00_sext_inreg_zexti32:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mulsu.w00 a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%a_trunc = trunc i64 %a to i32
|
|
%a_sext = sext i32 %a_trunc to i64
|
|
%b_zext = zext i32 %b to i64
|
|
%mul = mul i64 %a_sext, %b_zext
|
|
ret i64 %mul
|
|
}
|
|
|
|
define i64 @mulsu_w00_sext_inreg_zexti32_commute(i64 %a, i32 zeroext %b) nounwind {
|
|
; CHECK-LABEL: mulsu_w00_sext_inreg_zexti32_commute:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mulsu.w00 a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%a_trunc = trunc i64 %a to i32
|
|
%a_sext = sext i32 %a_trunc to i64
|
|
%b_zext = zext i32 %b to i64
|
|
%mul = mul i64 %b_zext, %a_sext
|
|
ret i64 %mul
|
|
}
|
|
|
|
; Test that we select pack.
|
|
define i64 @mm_usati_32_knownbits_i64(i64 %x, i64 %y) {
|
|
; CHECK-LABEL: mm_usati_32_knownbits_i64:
|
|
; CHECK: # %bb.0: # %entry
|
|
; CHECK-NEXT: usati a0, a0, 32
|
|
; CHECK-NEXT: pack a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
entry:
|
|
%0 = call i64 @llvm.smax.i64(i64 %x, i64 0)
|
|
%1 = call i64 @llvm.smin.i64(i64 %0, i64 4294967295)
|
|
%2 = shl i64 %y, 32
|
|
%3 = or i64 %1, %2
|
|
ret i64 %3
|
|
}
|
|
|
|
; Test USATI select patterns
|
|
define i3 @usati_i3_from_i64(i64 %x) {
|
|
; CHECK-LABEL: usati_i3_from_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: usati a0, a0, 3
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i64 %x, 7
|
|
%cmp2 = icmp sgt i64 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i3
|
|
%trunc = trunc i64 %x to i3
|
|
%sel = select i1 %cmp1, i3 %cmp2.ext, i3 %trunc
|
|
ret i3 %sel
|
|
}
|
|
|
|
define i5 @usati_i5_from_i64(i64 %x) {
|
|
; CHECK-LABEL: usati_i5_from_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: usati a0, a0, 5
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i64 %x, 31
|
|
%cmp2 = icmp sgt i64 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i5
|
|
%trunc = trunc i64 %x to i5
|
|
%sel = select i1 %cmp1, i5 %cmp2.ext, i5 %trunc
|
|
ret i5 %sel
|
|
}
|
|
|
|
define i7 @usati_i7_from_i64(i64 %x) {
|
|
; CHECK-LABEL: usati_i7_from_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: usati a0, a0, 7
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i64 %x, 127
|
|
%cmp2 = icmp sgt i64 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i7
|
|
%trunc = trunc i64 %x to i7
|
|
%sel = select i1 %cmp1, i7 %cmp2.ext, i7 %trunc
|
|
ret i7 %sel
|
|
}
|
|
|
|
define i8 @usati_i8_from_i64(i64 %x) {
|
|
; CHECK-LABEL: usati_i8_from_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: usati a0, a0, 8
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i64 %x, 255
|
|
%cmp2 = icmp sgt i64 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i8
|
|
%trunc = trunc i64 %x to i8
|
|
%sel = select i1 %cmp1, i8 %cmp2.ext, i8 %trunc
|
|
ret i8 %sel
|
|
}
|
|
|
|
define i10 @usati_i10_from_i64(i64 %x) {
|
|
; CHECK-LABEL: usati_i10_from_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: usati a0, a0, 10
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i64 %x, 1023
|
|
%cmp2 = icmp sgt i64 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i10
|
|
%trunc = trunc i64 %x to i10
|
|
%sel = select i1 %cmp1, i10 %cmp2.ext, i10 %trunc
|
|
ret i10 %sel
|
|
}
|
|
|
|
define i16 @usati_i16_from_i64(i64 %x) {
|
|
; CHECK-LABEL: usati_i16_from_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: usati a0, a0, 16
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i64 %x, 65535
|
|
%cmp2 = icmp sgt i64 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i16
|
|
%trunc = trunc i64 %x to i16
|
|
%sel = select i1 %cmp1, i16 %cmp2.ext, i16 %trunc
|
|
ret i16 %sel
|
|
}
|
|
|
|
define i20 @usati_i20_from_i64(i64 %x) {
|
|
; CHECK-LABEL: usati_i20_from_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: usati a0, a0, 20
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i64 %x, 1048575
|
|
%cmp2 = icmp sgt i64 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i20
|
|
%trunc = trunc i64 %x to i20
|
|
%sel = select i1 %cmp1, i20 %cmp2.ext, i20 %trunc
|
|
ret i20 %sel
|
|
}
|
|
|
|
define i32 @usati_i32_from_i64(i64 %x) {
|
|
; CHECK-LABEL: usati_i32_from_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: usati a0, a0, 32
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i64 %x, 4294967295
|
|
%cmp2 = icmp sgt i64 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i32
|
|
%trunc = trunc i64 %x to i32
|
|
%sel = select i1 %cmp1, i32 %cmp2.ext, i32 %trunc
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i40 @usati_i40_from_i64(i64 %x) {
|
|
; CHECK-LABEL: usati_i40_from_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: usati a0, a0, 40
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i64 %x, 1099511627775
|
|
%cmp2 = icmp sgt i64 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i40
|
|
%trunc = trunc i64 %x to i40
|
|
%sel = select i1 %cmp1, i40 %cmp2.ext, i40 %trunc
|
|
ret i40 %sel
|
|
}
|
|
|
|
define i48 @usati_i48_from_i64(i64 %x) {
|
|
; CHECK-LABEL: usati_i48_from_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: usati a0, a0, 48
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i64 %x, 281474976710655
|
|
%cmp2 = icmp sgt i64 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i48
|
|
%trunc = trunc i64 %x to i48
|
|
%sel = select i1 %cmp1, i48 %cmp2.ext, i48 %trunc
|
|
ret i48 %sel
|
|
}
|
|
|
|
define i56 @usati_i56_from_i64(i64 %x) {
|
|
; CHECK-LABEL: usati_i56_from_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: usati a0, a0, 56
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i64 %x, 72057594037927935
|
|
%cmp2 = icmp sgt i64 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i56
|
|
%trunc = trunc i64 %x to i56
|
|
%sel = select i1 %cmp1, i56 %cmp2.ext, i56 %trunc
|
|
ret i56 %sel
|
|
}
|
|
|
|
define i63 @usati_i63_from_i64(i64 %x) {
|
|
; CHECK-LABEL: usati_i63_from_i64:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: usati a0, a0, 63
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i64 %x, 9223372036854775807
|
|
%cmp2 = icmp sgt i64 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i63
|
|
%trunc = trunc i64 %x to i63
|
|
%sel = select i1 %cmp1, i63 %cmp2.ext, i63 %trunc
|
|
ret i63 %sel
|
|
}
|
|
|
|
; Test USATI with non-XLen source types (now supported by looking through truncates)
|
|
define i8 @usati_i8_from_i16(i16 %x) {
|
|
; CHECK-LABEL: usati_i8_from_i16:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: sext.h a0, a0
|
|
; CHECK-NEXT: usati a0, a0, 8
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i16 %x, 255
|
|
%cmp2 = icmp sgt i16 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i8
|
|
%trunc = trunc i16 %x to i8
|
|
%sel = select i1 %cmp1, i8 %cmp2.ext, i8 %trunc
|
|
ret i8 %sel
|
|
}
|
|
|
|
define i8 @usati_i8_from_i32(i32 %x) {
|
|
; CHECK-LABEL: usati_i8_from_i32:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: sext.w a0, a0
|
|
; CHECK-NEXT: usati a0, a0, 8
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i32 %x, 255
|
|
%cmp2 = icmp sgt i32 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i8
|
|
%trunc = trunc i32 %x to i8
|
|
%sel = select i1 %cmp1, i8 %cmp2.ext, i8 %trunc
|
|
ret i8 %sel
|
|
}
|
|
|
|
define i16 @usati_i16_from_i32(i32 %x) {
|
|
; CHECK-LABEL: usati_i16_from_i32:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: sext.w a0, a0
|
|
; CHECK-NEXT: usati a0, a0, 16
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i32 %x, 65535
|
|
%cmp2 = icmp sgt i32 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i16
|
|
%trunc = trunc i32 %x to i16
|
|
%sel = select i1 %cmp1, i16 %cmp2.ext, i16 %trunc
|
|
ret i16 %sel
|
|
}
|
|
|
|
define i16 @usati_i16_from_i48(i48 %x) {
|
|
; CHECK-LABEL: usati_i16_from_i48:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: slli a0, a0, 16
|
|
; CHECK-NEXT: srai a0, a0, 16
|
|
; CHECK-NEXT: usati a0, a0, 16
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i48 %x, 65535
|
|
%cmp2 = icmp sgt i48 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i16
|
|
%trunc = trunc i48 %x to i16
|
|
%sel = select i1 %cmp1, i16 %cmp2.ext, i16 %trunc
|
|
ret i16 %sel
|
|
}
|
|
|
|
define i32 @usati_i32_from_i48(i48 %x) {
|
|
; CHECK-LABEL: usati_i32_from_i48:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: slli a0, a0, 16
|
|
; CHECK-NEXT: srai a0, a0, 16
|
|
; CHECK-NEXT: usati a0, a0, 32
|
|
; CHECK-NEXT: ret
|
|
%cmp1 = icmp ugt i48 %x, 4294967295
|
|
%cmp2 = icmp sgt i48 %x, -1
|
|
%cmp2.ext = sext i1 %cmp2 to i32
|
|
%trunc = trunc i48 %x to i32
|
|
%sel = select i1 %cmp1, i32 %cmp2.ext, i32 %trunc
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i64 @macc_w00(i64 %rd, i32 %a, i32 %b) nounwind {
|
|
; CHECK-LABEL: macc_w00:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: macc.w00 a0, a1, a2
|
|
; CHECK-NEXT: ret
|
|
%aext = sext i32 %a to i64
|
|
%bext = sext i32 %b to i64
|
|
%mul = mul i64 %aext, %bext
|
|
%result = add i64 %rd, %mul
|
|
ret i64 %result
|
|
}
|
|
|
|
define i64 @macc_w00_commute(i64 %rd, i32 %a, i32 %b) nounwind {
|
|
; CHECK-LABEL: macc_w00_commute:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: macc.w00 a0, a1, a2
|
|
; CHECK-NEXT: ret
|
|
%aext = sext i32 %a to i64
|
|
%bext = sext i32 %b to i64
|
|
%mul = mul i64 %aext, %bext
|
|
%result = add i64 %mul, %rd
|
|
ret i64 %result
|
|
}
|
|
|
|
define i64 @maccu_w00(i64 %rd, i32 %a, i32 %b) nounwind {
|
|
; CHECK-LABEL: maccu_w00:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: maccu.w00 a0, a1, a2
|
|
; CHECK-NEXT: ret
|
|
%aext = zext i32 %a to i64
|
|
%bext = zext i32 %b to i64
|
|
%mul = mul i64 %aext, %bext
|
|
%result = add i64 %rd, %mul
|
|
ret i64 %result
|
|
}
|
|
|
|
define i64 @maccu_w00_commute(i64 %rd, i32 %a, i32 %b) nounwind {
|
|
; CHECK-LABEL: maccu_w00_commute:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: maccu.w00 a0, a1, a2
|
|
; CHECK-NEXT: ret
|
|
%aext = zext i32 %a to i64
|
|
%bext = zext i32 %b to i64
|
|
%mul = mul i64 %aext, %bext
|
|
%result = add i64 %mul, %rd
|
|
ret i64 %result
|
|
}
|
|
|
|
define i64 @maccsu_w00(i64 %rd, i32 %a, i32 %b) nounwind {
|
|
; CHECK-LABEL: maccsu_w00:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: maccsu.w00 a0, a1, a2
|
|
; CHECK-NEXT: ret
|
|
%aext = sext i32 %a to i64
|
|
%bext = zext i32 %b to i64
|
|
%mul = mul i64 %aext, %bext
|
|
%result = add i64 %rd, %mul
|
|
ret i64 %result
|
|
}
|
|
|
|
define i64 @maccsu_w00_commute(i64 %rd, i32 %a, i32 %b) nounwind {
|
|
; CHECK-LABEL: maccsu_w00_commute:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: maccsu.w00 a0, a1, a2
|
|
; CHECK-NEXT: ret
|
|
%aext = sext i32 %a to i64
|
|
%bext = zext i32 %b to i64
|
|
%mul = mul i64 %aext, %bext
|
|
%result = add i64 %mul, %rd
|
|
ret i64 %result
|
|
}
|
|
|
|
define i64 @maccsu_w00_swap_operands(i64 %rd, i32 %a, i32 %b) nounwind {
|
|
; CHECK-LABEL: maccsu_w00_swap_operands:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: maccsu.w00 a0, a2, a1
|
|
; CHECK-NEXT: ret
|
|
%aext = zext i32 %a to i64
|
|
%bext = sext i32 %b to i64
|
|
%mul = mul i64 %aext, %bext
|
|
%result = add i64 %rd, %mul
|
|
ret i64 %result
|
|
}
|
|
|
|
define i64 @maccsu_w00_swap_operands_commute(i64 %rd, i32 %a, i32 %b) nounwind {
|
|
; CHECK-LABEL: maccsu_w00_swap_operands_commute:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: maccsu.w00 a0, a2, a1
|
|
; CHECK-NEXT: ret
|
|
%aext = zext i32 %a to i64
|
|
%bext = sext i32 %b to i64
|
|
%mul = mul i64 %aext, %bext
|
|
%result = add i64 %mul, %rd
|
|
ret i64 %result
|
|
}
|
|
|
|
; Negative test: multiply result has multiple uses, should not combine to macc
|
|
define i64 @macc_w00_multiple_uses(i32 %a, i32 %b, i64 %c, ptr %out) nounwind {
|
|
; CHECK-LABEL: macc_w00_multiple_uses:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: mul.w00 a1, a0, a1
|
|
; CHECK-NEXT: add a0, a2, a1
|
|
; CHECK-NEXT: sd a1, 0(a3)
|
|
; CHECK-NEXT: ret
|
|
%aext = sext i32 %a to i64
|
|
%bext = sext i32 %b to i64
|
|
%mul = mul i64 %aext, %bext
|
|
%result = add i64 %c, %mul
|
|
store i64 %mul, ptr %out
|
|
ret i64 %result
|
|
}
|
|
|
|
; Test that pli.b is rematerialized rather than spilled
|
|
define i64 @test_pli_b_remat(ptr %p) nounwind {
|
|
; CHECK-LABEL: test_pli_b_remat:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: addi sp, sp, -112
|
|
; CHECK-NEXT: sd ra, 104(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s0, 96(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s1, 88(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s2, 80(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s3, 72(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s4, 64(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s5, 56(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s6, 48(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s7, 40(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s8, 32(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s9, 24(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s10, 16(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s11, 8(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: pli.b a1, 37
|
|
; CHECK-NEXT: sd a1, 0(a0)
|
|
; CHECK-NEXT: #APP
|
|
; CHECK-NEXT: #NO_APP
|
|
; CHECK-NEXT: pli.b a0, 37
|
|
; CHECK-NEXT: ld ra, 104(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s0, 96(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s1, 88(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s2, 80(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s3, 72(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s4, 64(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s5, 56(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s6, 48(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s7, 40(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s8, 32(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s9, 24(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s10, 16(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s11, 8(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: addi sp, sp, 112
|
|
; CHECK-NEXT: ret
|
|
store volatile i64 u0x2525252525252525, ptr %p
|
|
; Clobber all registers to force rematerialization
|
|
tail call void asm sideeffect "", "~{x1},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x18},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{x29},~{x30},~{x31}"()
|
|
; Use the constant again - it should be rematerialized, not spilled/reloaded
|
|
ret i64 u0x2525252525252525
|
|
}
|
|
|
|
; Test that pli.h is rematerialized rather than spilled
|
|
define i64 @test_pli_h_remat(ptr %p) nounwind {
|
|
; CHECK-LABEL: test_pli_h_remat:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: addi sp, sp, -112
|
|
; CHECK-NEXT: sd ra, 104(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s0, 96(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s1, 88(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s2, 80(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s3, 72(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s4, 64(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s5, 56(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s6, 48(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s7, 40(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s8, 32(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s9, 24(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s10, 16(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s11, 8(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: pli.h a1, 291
|
|
; CHECK-NEXT: sd a1, 0(a0)
|
|
; CHECK-NEXT: #APP
|
|
; CHECK-NEXT: #NO_APP
|
|
; CHECK-NEXT: pli.h a0, 291
|
|
; CHECK-NEXT: ld ra, 104(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s0, 96(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s1, 88(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s2, 80(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s3, 72(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s4, 64(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s5, 56(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s6, 48(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s7, 40(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s8, 32(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s9, 24(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s10, 16(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s11, 8(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: addi sp, sp, 112
|
|
; CHECK-NEXT: ret
|
|
store volatile i64 u0x0123012301230123, ptr %p
|
|
; Clobber all registers to force rematerialization
|
|
tail call void asm sideeffect "", "~{x1},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x18},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{x29},~{x30},~{x31}"()
|
|
; Use the constant again - it should be rematerialized, not spilled/reloaded
|
|
ret i64 u0x0123012301230123
|
|
}
|
|
|
|
; Test that plui.h is rematerialized rather than spilled
|
|
define i64 @test_plui_h_remat(ptr %p) nounwind {
|
|
; CHECK-LABEL: test_plui_h_remat:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: addi sp, sp, -112
|
|
; CHECK-NEXT: sd ra, 104(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s0, 96(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s1, 88(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s2, 80(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s3, 72(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s4, 64(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s5, 56(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s6, 48(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s7, 40(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s8, 32(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s9, 24(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s10, 16(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s11, 8(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: plui.h a1, -9
|
|
; CHECK-NEXT: sd a1, 0(a0)
|
|
; CHECK-NEXT: #APP
|
|
; CHECK-NEXT: #NO_APP
|
|
; CHECK-NEXT: plui.h a0, -9
|
|
; CHECK-NEXT: ld ra, 104(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s0, 96(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s1, 88(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s2, 80(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s3, 72(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s4, 64(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s5, 56(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s6, 48(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s7, 40(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s8, 32(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s9, 24(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s10, 16(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s11, 8(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: addi sp, sp, 112
|
|
; CHECK-NEXT: ret
|
|
store volatile i64 u0xfdc0fdc0fdc0fdc0, ptr %p
|
|
; Clobber all registers to force rematerialization
|
|
tail call void asm sideeffect "", "~{x1},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x18},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{x29},~{x30},~{x31}"()
|
|
; Use the constant again - it should be rematerialized, not spilled/reloaded
|
|
ret i64 u0xfdc0fdc0fdc0fdc0
|
|
}
|
|
|
|
; Test that pli.w is rematerialized rather than spilled
|
|
define i64 @test_pli_w_remat(ptr %p) nounwind {
|
|
; CHECK-LABEL: test_pli_w_remat:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: addi sp, sp, -112
|
|
; CHECK-NEXT: sd ra, 104(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s0, 96(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s1, 88(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s2, 80(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s3, 72(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s4, 64(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s5, 56(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s6, 48(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s7, 40(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s8, 32(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s9, 24(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s10, 16(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s11, 8(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: pli.w a1, -292
|
|
; CHECK-NEXT: sd a1, 0(a0)
|
|
; CHECK-NEXT: #APP
|
|
; CHECK-NEXT: #NO_APP
|
|
; CHECK-NEXT: pli.w a0, -292
|
|
; CHECK-NEXT: ld ra, 104(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s0, 96(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s1, 88(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s2, 80(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s3, 72(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s4, 64(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s5, 56(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s6, 48(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s7, 40(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s8, 32(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s9, 24(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s10, 16(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s11, 8(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: addi sp, sp, 112
|
|
; CHECK-NEXT: ret
|
|
store volatile i64 u0xfffffedcfffffedc, ptr %p
|
|
; Clobber all registers to force rematerialization
|
|
tail call void asm sideeffect "", "~{x1},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x18},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{x29},~{x30},~{x31}"()
|
|
; Use the constant again - it should be rematerialized, not spilled/reloaded
|
|
ret i64 u0xfffffedcfffffedc
|
|
}
|
|
|
|
; Test that plui.w is rematerialized rather than spilled
|
|
define i64 @test_plui_w_remat(ptr %p) nounwind {
|
|
; CHECK-LABEL: test_plui_w_remat:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: addi sp, sp, -112
|
|
; CHECK-NEXT: sd ra, 104(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s0, 96(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s1, 88(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s2, 80(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s3, 72(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s4, 64(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s5, 56(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s6, 48(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s7, 40(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s8, 32(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s9, 24(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s10, 16(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: sd s11, 8(sp) # 8-byte Folded Spill
|
|
; CHECK-NEXT: plui.w a1, 473
|
|
; CHECK-NEXT: sd a1, 0(a0)
|
|
; CHECK-NEXT: #APP
|
|
; CHECK-NEXT: #NO_APP
|
|
; CHECK-NEXT: plui.w a0, 473
|
|
; CHECK-NEXT: ld ra, 104(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s0, 96(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s1, 88(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s2, 80(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s3, 72(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s4, 64(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s5, 56(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s6, 48(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s7, 40(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s8, 32(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s9, 24(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s10, 16(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: ld s11, 8(sp) # 8-byte Folded Reload
|
|
; CHECK-NEXT: addi sp, sp, 112
|
|
; CHECK-NEXT: ret
|
|
store volatile i64 u0x7640000076400000, ptr %p
|
|
; Clobber all registers to force rematerialization
|
|
tail call void asm sideeffect "", "~{x1},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x18},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{x29},~{x30},~{x31}"()
|
|
; Use the constant again - it should be rematerialized, not spilled/reloaded
|
|
ret i64 u0x7640000076400000
|
|
}
|
|
|
|
; The 0x0101010101010101 can be materialized with pli.b
|
|
; The multiply makes the upper 10 bits of the and result unneeded
|
|
; causing the mask to become 0x0001010101010101. Make sure we can still match
|
|
; the pli.b
|
|
define i64 @and_mul_32bitsplat(i64 %x) {
|
|
; CHECK-LABEL: and_mul_32bitsplat:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: pli.b a1, 1
|
|
; CHECK-NEXT: lui a2, 65664
|
|
; CHECK-NEXT: and a0, a0, a1
|
|
; CHECK-NEXT: addi a1, a2, 1024
|
|
; CHECK-NEXT: slli a2, a1, 27
|
|
; CHECK-NEXT: add a1, a1, a2
|
|
; CHECK-NEXT: mul a0, a0, a1
|
|
; CHECK-NEXT: ret
|
|
%a = and i64 %x, u0x0101010101010101
|
|
%b = mul i64 %a, u0x0080402010080400
|
|
ret i64 %b
|
|
}
|