blob: 34e54f1a8c79a6ce9a823ea3359220de026b4011 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc -mtriple=riscv32 -mattr=+d < %s | FileCheck %s --check-prefix=RV32
; RUN: llc -mtriple=riscv64 -mattr=+d < %s | FileCheck %s --check-prefix=RV64
; Fold (sub 0, (srl (and X, (1 << ShAmt)), ShAmt)) ->
; (sra (shl X, bits-1-ShAmt), bits-1)
; This turns an and+srl+neg sequence into a sign-extension of a single bit
; via shl+sra. llvm.is.fpclass with a single-bit mask is a convenient way to
; generate the and+srl+sub pattern.
define i32 @is_snan_sext_f64(double %x) nounwind {
; RV32-LABEL: is_snan_sext_f64:
; RV32: # %bb.0:
; RV32-NEXT: fclass.d a0, fa0
; RV32-NEXT: slli a0, a0, 23
; RV32-NEXT: srai a0, a0, 31
; RV32-NEXT: ret
;
; RV64-LABEL: is_snan_sext_f64:
; RV64: # %bb.0:
; RV64-NEXT: fclass.d a0, fa0
; RV64-NEXT: slli a0, a0, 55
; RV64-NEXT: srai a0, a0, 63
; RV64-NEXT: ret
%c = call i1 @llvm.is.fpclass.f64(double %x, i32 1) ; fcSNan
%s = select i1 %c, i32 -1, i32 0
ret i32 %s
}
define i32 @is_snan_sext_f32(float %x) nounwind {
; RV32-LABEL: is_snan_sext_f32:
; RV32: # %bb.0:
; RV32-NEXT: fclass.s a0, fa0
; RV32-NEXT: slli a0, a0, 23
; RV32-NEXT: srai a0, a0, 31
; RV32-NEXT: ret
;
; RV64-LABEL: is_snan_sext_f32:
; RV64: # %bb.0:
; RV64-NEXT: fclass.s a0, fa0
; RV64-NEXT: slli a0, a0, 55
; RV64-NEXT: srai a0, a0, 63
; RV64-NEXT: ret
%c = call i1 @llvm.is.fpclass.f32(float %x, i32 1) ; fcSNan
%s = select i1 %c, i32 -1, i32 0
ret i32 %s
}
; The and gets combined away by DAGCombiner before performSUBCombine runs
; (it can prove the high bits are already zero), so this case doesn't match
; the and+srl pattern and keeps the srli+neg form instead.
define i32 @is_qnan_sext_f64(double %x) nounwind {
; RV32-LABEL: is_qnan_sext_f64:
; RV32: # %bb.0:
; RV32-NEXT: fclass.d a0, fa0
; RV32-NEXT: srli a0, a0, 9
; RV32-NEXT: neg a0, a0
; RV32-NEXT: ret
;
; RV64-LABEL: is_qnan_sext_f64:
; RV64: # %bb.0:
; RV64-NEXT: fclass.d a0, fa0
; RV64-NEXT: srli a0, a0, 9
; RV64-NEXT: neg a0, a0
; RV64-NEXT: ret
%c = call i1 @llvm.is.fpclass.f64(double %x, i32 2) ; fcQNan
%s = select i1 %c, i32 -1, i32 0
ret i32 %s
}
define i32 @is_posinf_sext_f64(double %x) nounwind {
; RV32-LABEL: is_posinf_sext_f64:
; RV32: # %bb.0:
; RV32-NEXT: fclass.d a0, fa0
; RV32-NEXT: slli a0, a0, 24
; RV32-NEXT: srai a0, a0, 31
; RV32-NEXT: ret
;
; RV64-LABEL: is_posinf_sext_f64:
; RV64: # %bb.0:
; RV64-NEXT: fclass.d a0, fa0
; RV64-NEXT: slli a0, a0, 56
; RV64-NEXT: srai a0, a0, 63
; RV64-NEXT: ret
%c = call i1 @llvm.is.fpclass.f64(double %x, i32 512) ; fcPosInf
%s = select i1 %c, i32 -1, i32 0
ret i32 %s
}
; A multi-bit mask isn't a single-bit extraction, so this should not fold to
; the shl+sra pattern.
define i32 @is_nan_sext_f64_no_fold(double %x) nounwind {
; RV32-LABEL: is_nan_sext_f64_no_fold:
; RV32: # %bb.0:
; RV32-NEXT: fclass.d a0, fa0
; RV32-NEXT: andi a0, a0, 768
; RV32-NEXT: seqz a0, a0
; RV32-NEXT: addi a0, a0, -1
; RV32-NEXT: ret
;
; RV64-LABEL: is_nan_sext_f64_no_fold:
; RV64: # %bb.0:
; RV64-NEXT: fclass.d a0, fa0
; RV64-NEXT: andi a0, a0, 768
; RV64-NEXT: seqz a0, a0
; RV64-NEXT: addi a0, a0, -1
; RV64-NEXT: ret
%c = call i1 @llvm.is.fpclass.f64(double %x, i32 3) ; fcNan (two bits)
%s = select i1 %c, i32 -1, i32 0
ret i32 %s
}
declare i1 @llvm.is.fpclass.f64(double, i32)
declare i1 @llvm.is.fpclass.f32(float, i32)