Files
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

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
}