Index: clang/include/clang/Basic/CodeGenOptions.h =================================================================== --- clang/include/clang/Basic/CodeGenOptions.h +++ clang/include/clang/Basic/CodeGenOptions.h @@ -16,6 +16,7 @@ #include "clang/Basic/DebugInfoOptions.h" #include "clang/Basic/Sanitizers.h" #include "clang/Basic/XRayInstr.h" +#include "llvm/ADT/FloatingPointMode.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Regex.h" #include "llvm/Target/TargetOptions.h" @@ -162,8 +163,8 @@ /// The ABI to use for passing floating point arguments. std::string FloatABI; - /// The floating-point denormal mode to use. - std::string FPDenormalMode; + /// The floating-point subnormal mode to use. + llvm::SubnormalMode FPSubnormalMode = llvm::SubnormalMode::Invalid; /// The float precision limit to use, if non-empty. std::string LimitFloatPrecision; Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -1732,8 +1732,9 @@ if (CodeGenOpts.NullPointerIsValid) FuncAttrs.addAttribute("null-pointer-is-valid", "true"); - if (!CodeGenOpts.FPDenormalMode.empty()) - FuncAttrs.addAttribute("denormal-fp-math", CodeGenOpts.FPDenormalMode); + if (CodeGenOpts.FPSubnormalMode != llvm::SubnormalMode::Invalid) + FuncAttrs.addAttribute("denormal-fp-math", + llvm::subnormalModeName(CodeGenOpts.FPSubnormalMode)); FuncAttrs.addAttribute("no-trapping-math", llvm::toStringRef(CodeGenOpts.NoTrappingMath)); Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -1261,13 +1261,8 @@ if (Arg *A = Args.getLastArg(OPT_fdenormal_fp_math_EQ)) { StringRef Val = A->getValue(); - if (Val == "ieee") - Opts.FPDenormalMode = "ieee"; - else if (Val == "preserve-sign") - Opts.FPDenormalMode = "preserve-sign"; - else if (Val == "positive-zero") - Opts.FPDenormalMode = "positive-zero"; - else + Opts.FPSubnormalMode = llvm::parseSubnormalFPAttribute(Val); + if (Opts.FPSubnormalMode == llvm::SubnormalMode::Invalid) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; } Index: llvm/include/llvm/ADT/FloatingPointMode.h =================================================================== --- /dev/null +++ llvm/include/llvm/ADT/FloatingPointMode.h @@ -0,0 +1,62 @@ +//===- llvm/Support/FloatingPointMode.h -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Utilities for dealing with flags related to floating point mode controls. +// +//===----------------------------------------------------------------------===/ + +#ifndef LLVM_FLOATINGPOINTMODE_H +#define LLVM_FLOATINGPOINTMODE_H + +#include "llvm/ADT/StringSwitch.h" + +namespace llvm { + +/// Represent handled modes for subnormal (aka denormal) modes in the floating +/// point environment. +enum class SubnormalMode { + Invalid = -1, + + /// IEEE-754 subnormal numbers preserved. + IEEE, + + /// The sign of a flushed-to-zero number is preserved in the sign of 0 + PreserveSign, + + /// Subnormals are flushed to positive zero. + PositiveZero +}; + +/// Parse the expected names from the denormal-fp-math attribute. +inline SubnormalMode parseSubnormalFPAttribute(StringRef Str) { + // Assume ieee on unspecified attribute. + return StringSwitch(Str) + .Cases("", "ieee", SubnormalMode::IEEE) + .Case("preserve-sign", SubnormalMode::PreserveSign) + .Case("positive-zero", SubnormalMode::PositiveZero) + .Default(SubnormalMode::Invalid); +} + +/// Return the name used for the subnormal handling mode used by the the +/// expected names from the denormal-fp-math attribute. +inline StringRef subnormalModeName(SubnormalMode Mode) { + switch (Mode) { + case SubnormalMode::IEEE: + return "ieee"; + case SubnormalMode::PreserveSign: + return "preserve-sign"; + case SubnormalMode::PositiveZero: + return "positive-zero"; + default: + return ""; + } +} + +} + +#endif // LLVM_FLOATINGPOINTMODE_H Index: llvm/include/llvm/CodeGen/MachineFunction.h =================================================================== --- llvm/include/llvm/CodeGen/MachineFunction.h +++ llvm/include/llvm/CodeGen/MachineFunction.h @@ -20,6 +20,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FloatingPointMode.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" @@ -579,6 +580,10 @@ return const_cast(this)->getInfo(); } + /// Returns the subnormal handling type for the default rounding mode of the + /// function. + SubnormalMode getSubnormalMode() const; + /// getBlockNumbered - MachineBasicBlocks are automatically numbered when they /// are inserted into the machine function. The block number for a machine /// basic block can be found by using the MBB::getNumber method, this method Index: llvm/lib/CodeGen/MachineFunction.cpp =================================================================== --- llvm/lib/CodeGen/MachineFunction.cpp +++ llvm/lib/CodeGen/MachineFunction.cpp @@ -270,6 +270,13 @@ return JumpTableInfo; } +SubnormalMode MachineFunction::getSubnormalMode() const { + // TODO: Should probably avoid the connection to the IR and store directly + // in the MachineFunction. + Attribute Attr = F.getFnAttribute("denormal-fp-math"); + return parseSubnormalFPAttribute(Attr.getValueAsString()); +} + /// Should we be emitting segmented stack stuff for the function bool MachineFunction::shouldSplitStack() const { return getFunction().hasFnAttribute("split-stack"); Index: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -20452,9 +20452,8 @@ SDLoc DL(Op); EVT CCVT = getSetCCResultType(VT); ISD::NodeType SelOpcode = VT.isVector() ? ISD::VSELECT : ISD::SELECT; - const Function &F = DAG.getMachineFunction().getFunction(); - Attribute Denorms = F.getFnAttribute("denormal-fp-math"); - if (Denorms.getValueAsString().equals("ieee")) { + SubnormalMode SubnormMode = DAG.getMachineFunction().getSubnormalMode(); + if (SubnormMode == SubnormalMode::IEEE) { // fabs(X) < SmallestNormal ? 0.0 : Est const fltSemantics &FltSem = DAG.EVTToAPFloatSemantics(VT); APFloat SmallestNorm = APFloat::getSmallestNormalized(FltSem); @@ -20464,6 +20463,8 @@ SDValue IsDenorm = DAG.getSetCC(DL, CCVT, Fabs, NormC, ISD::SETLT); Est = DAG.getNode(SelOpcode, DL, VT, IsDenorm, FPZero, Est); } else { + assert(SubnormMode == SubnormalMode::PreserveSign || + SubnormMode == SubnormalMode::PositiveZero); // X == 0.0 ? 0.0 : Est SDValue FPZero = DAG.getConstantFP(0.0, DL, VT); SDValue IsZero = DAG.getSetCC(DL, CCVT, Op, FPZero, ISD::SETEQ); Index: llvm/unittests/ADT/CMakeLists.txt =================================================================== --- llvm/unittests/ADT/CMakeLists.txt +++ llvm/unittests/ADT/CMakeLists.txt @@ -20,6 +20,7 @@ DirectedGraphTest.cpp EquivalenceClassesTest.cpp FallibleIteratorTest.cpp + FloatingPointMode.cpp FoldingSet.cpp FunctionExtrasTest.cpp FunctionRefTest.cpp Index: llvm/unittests/ADT/FloatingPointMode.cpp =================================================================== --- /dev/null +++ llvm/unittests/ADT/FloatingPointMode.cpp @@ -0,0 +1,33 @@ +//===- llvm/unittest/ADT/FloatingPointMode.cpp ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/FloatingPointMode.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(FloatingPointModeTest, ParseSubnormalFPAttribute) { + EXPECT_EQ(SubnormalMode::IEEE, parseSubnormalFPAttribute("ieee")); + EXPECT_EQ(SubnormalMode::IEEE, parseSubnormalFPAttribute("")); + EXPECT_EQ(SubnormalMode::PreserveSign, + parseSubnormalFPAttribute("preserve-sign")); + EXPECT_EQ(SubnormalMode::PositiveZero, + parseSubnormalFPAttribute("positive-zero")); + EXPECT_EQ(SubnormalMode::Invalid, parseSubnormalFPAttribute("foo")); +} + +TEST(FloatingPointModeTest, SubnormalAttributeName) { + EXPECT_EQ("ieee", subnormalModeName(SubnormalMode::IEEE)); + EXPECT_EQ("preserve-sign", subnormalModeName(SubnormalMode::PreserveSign)); + EXPECT_EQ("positive-zero", subnormalModeName(SubnormalMode::PositiveZero)); + EXPECT_EQ("", subnormalModeName(SubnormalMode::Invalid)); +} + +}