Index: include/llvm/Target/TargetLowering.h =================================================================== --- include/llvm/Target/TargetLowering.h +++ include/llvm/Target/TargetLowering.h @@ -887,6 +887,12 @@ /// reduce runtime. virtual bool ShouldShrinkFPConstant(EVT) const { return true; } + /// If true (and ShouldShrinkFPConstant is also true), then instruction + /// selection should shrink SNaN constants. This is needeed for architectures + /// (e.g. SystemZ) in which FP extending loads of a SNaN result in a QNaN + /// instead. + virtual bool ShouldShrinkSNaNConstant() const { return true; } + // Return true if it is profitable to reduce the given load node to a smaller // type. // Index: lib/CodeGen/SelectionDAG/LegalizeDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -259,19 +259,33 @@ (VT == MVT::f64) ? MVT::i64 : MVT::i32); } + APFloat APF = CFP->getValueAPF(); EVT OrigVT = VT; EVT SVT = VT; - while (SVT != MVT::f32 && SVT != MVT::f16) { - SVT = (MVT::SimpleValueType)(SVT.getSimpleVT().SimpleTy - 1); - if (ConstantFPSDNode::isValueValidForType(SVT, CFP->getValueAPF()) && - // Only do this if the target has a native EXTLOAD instruction from - // smaller type. - TLI.isLoadExtLegal(ISD::EXTLOAD, OrigVT, SVT) && - TLI.ShouldShrinkFPConstant(OrigVT)) { - Type *SType = SVT.getTypeForEVT(*DAG.getContext()); - LLVMC = cast(ConstantExpr::getFPTrunc(LLVMC, SType)); - VT = SVT; - Extend = true; + bool AttemptShrink = true; + + if (!TLI.ShouldShrinkSNaNConstant()) { + // Check if the FP value is a SNaN, and if so, don't shrink + APFloat SNaN = APFloat::getSNaN(APF.getSemantics()); + + if (APF.bitwiseIsEqual(SNaN)) { + AttemptShrink = false; + } + } + + if (AttemptShrink) { + while (SVT != MVT::f32 && SVT != MVT::f16) { + SVT = (MVT::SimpleValueType)(SVT.getSimpleVT().SimpleTy - 1); + if (ConstantFPSDNode::isValueValidForType(SVT, APF) && + // Only do this if the target has a native EXTLOAD instruction from + // smaller type. + TLI.isLoadExtLegal(ISD::EXTLOAD, OrigVT, SVT) && + TLI.ShouldShrinkFPConstant(OrigVT)) { + Type *SType = SVT.getTypeForEVT(*DAG.getContext()); + LLVMC = cast(ConstantExpr::getFPTrunc(LLVMC, SType)); + VT = SVT; + Extend = true; + } } } Index: lib/Target/SystemZ/SystemZISelLowering.h =================================================================== --- lib/Target/SystemZ/SystemZISelLowering.h +++ lib/Target/SystemZ/SystemZISelLowering.h @@ -486,6 +486,10 @@ return true; } + bool ShouldShrinkSNaNConstant() const override { + return false; + } + private: const SystemZSubtarget &Subtarget; Index: test/CodeGen/SystemZ/fp-const-10.ll =================================================================== --- test/CodeGen/SystemZ/fp-const-10.ll +++ test/CodeGen/SystemZ/fp-const-10.ll @@ -0,0 +1,15 @@ +; Test loads of SNaN. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +; Test that we don't do an FP extending load, as this would result in a +; converstion to QNaN. +define double @f1() { +; CHECK-LABEL: .LCPI0_0 +; CHECK: .quad 9219994337134247936 +; CHECK-LABEL: f1: +; CHECK: larl %r1, .LCPI0_0 +; CHECK-NOT: ldeb %f0, 0(%r1) +; CHECK: ld %f0, 0(%r1) + ret double 0x7FF4000000000000 +}