| ; 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) |