Index: lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.cpp +++ lib/Target/AArch64/AArch64ISelLowering.cpp @@ -5426,11 +5426,14 @@ } bool AArch64TargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { - // We can materialize #0.0 as fmov $Rd, XZR for 64-bit and 32-bit cases. + // We can materialize #0.0 and #INF as fmov $Rd, XZR for 64-bit and 32-bit + // cases. // FIXME: We should be able to handle f128 as well with a clever lowering. - if (Imm.isPosZero() && (VT == MVT::f64 || VT == MVT::f32 || - (VT == MVT::f16 && Subtarget->hasFullFP16()))) { - LLVM_DEBUG(dbgs() << "Legal " << VT.getEVTString() << " imm value: 0\n"); + if ((Imm.isPosZero() || Imm.isInfinity()) && + (VT == MVT::f64 || VT == MVT::f32 || + (VT == MVT::f16 && Subtarget->hasFullFP16()))) { + LLVM_DEBUG(dbgs() << "Legal " << VT.getEVTString() << " imm value: " + << (Imm.isPosZero() ? "0" : "Inf") << "\n"); return true; } Index: test/CodeGen/AArch64/isinf.ll =================================================================== --- /dev/null +++ test/CodeGen/AArch64/isinf.ll @@ -0,0 +1,47 @@ +; RUN: llc -mtriple=aarch64-none-linux-gnu -mattr=+neon < %s -o -| FileCheck %s + +declare float @llvm.fabs.f32(float) +declare double @llvm.fabs.f64(double) +declare fp128 @llvm.fabs.f128(fp128) + +; Check if INFINITY for float is materialized +define i32 @replace_isinf_call_f32(float %x) { +; CHECK-LABEL: replace_isinf_call_f32: +; CHECK: orr [[INFSCALARREG:w[0-9]+]], wzr, #0x7f800000 +; CHECK-NEXT: fabs [[ABS:s[0-9]+]], s0 +; CHECK-NEXT: fmov [[INFREG:s[0-9]+]], [[INFSCALARREG]] +; CHECK-NEXT: fcmp [[ABS]], [[INFREG]] +; CHECK-NEXT: cset w0, eq + %abs = tail call float @llvm.fabs.f32(float %x) + %cmpinf = fcmp oeq float %abs, 0x7FF0000000000000 + %ret = zext i1 %cmpinf to i32 + ret i32 %ret +} + +; Check if INFINITY for double is materialized +define i32 @replace_isinf_call_f64(double %x) { +; CHECK-LABEL: replace_isinf_call_f64: +; CHECK: orr [[INFSCALARREG:x[0-9]+]], xzr, #0x7ff0000000000000 +; CHECK-NEXT: fabs [[ABS:d[0-9]+]], d0 +; CHECK-NEXT: fmov [[INFREG:d[0-9]+]], [[INFSCALARREG]] +; CHECK-NEXT: fcmp [[ABS]], [[INFREG]] +; CHECK-NEXT: cset w0, eq + %abs = tail call double @llvm.fabs.f64(double %x) + %cmpinf = fcmp oeq double %abs, 0x7FF0000000000000 + %ret = zext i1 %cmpinf to i32 + ret i32 %ret +} + +; For long double it still requires loading the constant. +define i32 @replace_isinf_call_f128(fp128 %x) { +; CHECK-LABEL: replace_isinf_call_f128: +; CHECK: adrp [[ADDR:x[0-9]+]], [[CSTLABEL:.LCP.*]] +; CHECK: ldr q1, {{[[]}}[[ADDR]], :lo12:[[CSTLABEL]]{{[]]}} +; CHECK: bl __eqtf2 +; CHECK: cmp w0, #0 +; CHECK: cset w0, eq + %abs = tail call fp128 @llvm.fabs.f128(fp128 %x) + %cmpinf = fcmp oeq fp128 %abs, 0xL00000000000000007FFF000000000000 + %ret = zext i1 %cmpinf to i32 + ret i32 %ret +} Index: test/CodeGen/AArch64/known-never-nan.ll =================================================================== --- test/CodeGen/AArch64/known-never-nan.ll +++ test/CodeGen/AArch64/known-never-nan.ll @@ -28,13 +28,13 @@ define float @not_fmaxnm_maybe_nan(i32 %i1, i32 %i2) #0 { ; CHECK-LABEL: not_fmaxnm_maybe_nan: ; CHECK: // %bb.0: -; CHECK-NEXT: adrp x8, .LCPI1_0 -; CHECK-NEXT: ldr s0, [x8, :lo12:.LCPI1_0] -; CHECK-NEXT: ucvtf s1, w0 -; CHECK-NEXT: ucvtf s2, w1 -; CHECK-NEXT: fmov s3, #17.00000000 -; CHECK-NEXT: fmul s0, s1, s0 -; CHECK-NEXT: fadd s1, s2, s3 +; CHECK-NEXT: orr w8, wzr, #0xff800000 +; CHECK-NEXT: ucvtf s0, w0 +; CHECK-NEXT: ucvtf s1, w1 +; CHECK-NEXT: fmov s2, #17.00000000 +; CHECK-NEXT: fmov s3, w8 +; CHECK-NEXT: fmul s0, s0, s3 +; CHECK-NEXT: fadd s1, s1, s2 ; CHECK-NEXT: fcmp s0, s1 ; CHECK-NEXT: fcsel s0, s0, s1, pl ; CHECK-NEXT: ret