From 134bec27226ab1d37cff44b04cef73b67321601b Mon Sep 17 00:00:00 2001 From: James Molloy Date: Tue, 11 Aug 2015 09:12:57 +0000 Subject: Add support for floating-point minnum and maxnum The select pattern recognition in ValueTracking (as used by InstCombine and SelectionDAGBuilder) only knew about integer patterns. This teaches it about minimum and maximum operations. matchSelectPattern() has been extended to return a struct containing the existing Flavor and a new enum defining the pattern's behavior when given one NaN operand. C minnum() is defined to return the non-NaN operand in this case, but the idiomatic C "a < b ? a : b" would return the NaN operand. ARM and AArch64 at least have different instructions for these different cases. llvm-svn: 244580 --- llvm/unittests/Analysis/ValueTrackingTest.cpp | 148 ++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 llvm/unittests/Analysis/ValueTrackingTest.cpp (limited to 'llvm/unittests/Analysis/ValueTrackingTest.cpp') diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp new file mode 100644 index 00000000000..b5ad01968b9 --- /dev/null +++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp @@ -0,0 +1,148 @@ +//===- ValueTrackingTest.cpp - ValueTracking tests ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SourceMgr.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class MatchSelectPatternTest : public testing::Test { +protected: + void parseAssembly(const char *Assembly) { + SMDiagnostic Error; + M = parseAssemblyString(Assembly, Error, getGlobalContext()); + + std::string errMsg; + raw_string_ostream os(errMsg); + Error.print("", os); + + // A failure here means that the test itself is buggy. + if (!M) + report_fatal_error(os.str()); + + Function *F = M->getFunction("test"); + if (F == nullptr) + report_fatal_error("Test must have a function named @test"); + + A = nullptr; + for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { + if (I->hasName()) { + if (I->getName() == "A") + A = &*I; + } + } + if (A == nullptr) + report_fatal_error("@test must have an instruction %A"); + } + + void expectPattern(const SelectPatternResult &P) { + Value *LHS, *RHS; + Instruction::CastOps CastOp; + SelectPatternResult R = matchSelectPattern(A, LHS, RHS, &CastOp); + EXPECT_EQ(P.Flavor, R.Flavor); + EXPECT_EQ(P.NaNBehavior, R.NaNBehavior); + EXPECT_EQ(P.Ordered, R.Ordered); + } + + std::unique_ptr M; + Instruction *A, *B; +}; + +} + +TEST_F(MatchSelectPatternTest, SimpleFMin) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp ult float %a, 5.0\n" + " %A = select i1 %1, float %a, float 5.0\n" + " ret float %A\n" + "}\n"); + expectPattern({SPF_FMINNUM, SPNB_RETURNS_NAN, false}); +} + +TEST_F(MatchSelectPatternTest, SimpleFMax) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp ogt float %a, 5.0\n" + " %A = select i1 %1, float %a, float 5.0\n" + " ret float %A\n" + "}\n"); + expectPattern({SPF_FMAXNUM, SPNB_RETURNS_OTHER, true}); +} + +TEST_F(MatchSelectPatternTest, SwappedFMax) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp olt float 5.0, %a\n" + " %A = select i1 %1, float %a, float 5.0\n" + " ret float %A\n" + "}\n"); + expectPattern({SPF_FMAXNUM, SPNB_RETURNS_OTHER, false}); +} + +TEST_F(MatchSelectPatternTest, SwappedFMax2) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp olt float %a, 5.0\n" + " %A = select i1 %1, float 5.0, float %a\n" + " ret float %A\n" + "}\n"); + expectPattern({SPF_FMAXNUM, SPNB_RETURNS_NAN, false}); +} + +TEST_F(MatchSelectPatternTest, SwappedFMax3) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp ult float %a, 5.0\n" + " %A = select i1 %1, float 5.0, float %a\n" + " ret float %A\n" + "}\n"); + expectPattern({SPF_FMAXNUM, SPNB_RETURNS_OTHER, true}); +} + +TEST_F(MatchSelectPatternTest, FastFMin) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp nnan olt float %a, 5.0\n" + " %A = select i1 %1, float %a, float 5.0\n" + " ret float %A\n" + "}\n"); + expectPattern({SPF_FMINNUM, SPNB_RETURNS_ANY, false}); +} + +TEST_F(MatchSelectPatternTest, FMinConstantZero) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp ole float %a, 0.0\n" + " %A = select i1 %1, float %a, float 0.0\n" + " ret float %A\n" + "}\n"); + // This shouldn't be matched, as %a could be -0.0. + expectPattern({SPF_UNKNOWN, SPNB_NA, false}); +} + +TEST_F(MatchSelectPatternTest, FMinConstantZeroNsz) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp nsz ole float %a, 0.0\n" + " %A = select i1 %1, float %a, float 0.0\n" + " ret float %A\n" + "}\n"); + // But this should be, because we've ignored signed zeroes. + expectPattern({SPF_FMINNUM, SPNB_RETURNS_OTHER, true}); +} -- cgit v1.2.3