[PATCH] Flag to enable IEEE-754 friendly FP optimizations
Sergey Dmitrouk
sdmitrouk at accesssoftek.com
Tue May 26 09:43:22 PDT 2015
Hi there,
Nope, I didn't forget about these changes :) Ping!
Patches rebased onto ToT can be found in the attachment.
--
Sergey
On Fri, Mar 27, 2015 at 09:13:44AM -0700, Mehdi Amini wrote:
> Hi Sergey,
>
> I’m sorry that in 6 weeks nobody was able to approve your patches despite your pings.
>
> The code LGTM, but I don’t feel qualified enough to approve the global direction where this leads and I rather have someone else reviewing the “conceptual” part.
>
> Add CC Hal, who was involved at the beginning of the thread.
>
> Best,
>
> —
> Mehdi
>
> > On Mar 26, 2015, at 4:28 AM, Sergey Dmitrouk <sdmitrouk at accesssoftek.com> wrote:
> >
> > Ping.
> >
> > On Mon, Mar 16, 2015 at 09:55:45PM +0200, Sergey Dmitrouk wrote:
> >> Gentle ping.
> >>
> >> On Thu, Feb 26, 2015 at 01:33:19PM +0200, Sergey Dmitrouk wrote:
> >>> Ping.
> >>>
> >>> On Thu, Feb 19, 2015 at 05:34:26PM +0200, Sergey Dmitrouk wrote:
> >>>> Ping.
> >>>>
> >>>> On Tue, Feb 10, 2015 at 08:12:13PM +0200, Sergey Dmitrouk wrote:
> >>>>> Attached is alternative fix for InstCombine hanging, it disables only a
> >>>>> couple of conversions of "fadd" into "fsub" to break the loop.
> >>>>>
> >>>>> Modifying dyn_castFNegVal() directly causes some unit tests to fail, so
> >>>>> absence of checks seems to be intensional to enable more transformations.
> >>>>> As there exist "fsub" to "fadd" transformations and vice versa, making
> >>>>> some forms as canonical would disable at least one of them. So the
> >>>>> patch disables replacements of "fadd" with "fsub" for "fadd"
> >>>>> instructions marked with floating-point environment access flags.
> >>>>>
> >>>>> Regards,
> >>>>> Sergey
> >>>>>
> >>>>> On Thu, Feb 05, 2015 at 07:56:56PM +0200, Sergey Dmitrouk wrote:
> >>>>>> Hello,
> >>>>>>
> >>>>>> Thanks for reviewing this.
> >>>>>>
> >>>>>> On Wed, Feb 04, 2015 at 10:42:35AM -0800, Mehdi Amini wrote:
> >>>>>>> Patch 1:
> >>>>>>>
> >>>>>>> The comment for:
> >>>>>>> + unsigned AllowFPExceptAccess : 1;
> >>>>>>> mentions rounding and the comment for:
> >>>>>>> + unsigned AllowFPRoundAccess : 1;
> >>>>>>> mentions exceptions, they are reversed.
> >>>>>>
> >>>>>> Updated.
> >>>>>>
> >>>>>>> Patch 2:
> >>>>>>>
> >>>>>>> Is kexc or kround flag allowed to be present at the same time as fast?
> >>>>>>
> >>>>>> Yes, currently they are. There is no particular reason for this except
> >>>>>> for me not being able to decide whether "fast" should reset new flags or
> >>>>>> not. Left it unrelated to each other as they are unlikely to be used at
> >>>>>> the same time, ready to change it if you have any suggestions.
> >>>>>>
> >>>>>>> Patch 3:
> >>>>>>>
> >>>>>>> isSafeToOptimizeFPOp() is not clear to me, especially how TLI->hasFloatingPointExceptions() disable any check, including rounding, while the description of this flag is "Whether the target supports or cares about preserving floating point exception behavior”, which seems orthogonal to getTarget().Options.AllowFPRoundAccess?
> >>>>>>> I assume it is done this way to keep existing behavior? Is it transitional?
> >>>>>>
> >>>>>> That's a mistake, it was fine until recent change for rounding when I
> >>>>>> reordered if statements incorrectly. Thanks.
> >>>>>>
> >>>>>>> Patch 4:
> >>>>>>>
> >>>>>>> isSafeToSpeculativelyExecute(), comment might deserve to be updated , I don’t think it is true anymore with respect to rounding:
> >>>>>>> "Return true if the instruction does not have any effects besides calculating the result and does not have undefined behavior”.
> >>>>>>
> >>>>>> Updated.
> >>>>>>
> >>>>>>> canTrap(), again preserving the dynamic “rounding” is included in “trap”? Maybe the comment could be updated because it does not seem obvious to me.
> >>>>>>
> >>>>>> Actually, rounding flag wasn't even used and exceptions flag was
> >>>>>> unnecessary, so I just reverted that part. It was required with flags
> >>>>>> being detached from instructions, but now that they are part of
> >>>>>> fast-math flags checking constant expressions should be no-operation
> >>>>>> (operations that go against flags must not be converted to constant
> >>>>>> expressions).
> >>>>>>
> >>>>>>> Patch 10: if you really want to test it, maybe the C++ unittests can do the job?
> >>>>>>
> >>>>>> Thanks, added a unit-test and a correction for "frem" instruction.
> >>>>>>
> >>>>>>> Patch 12: haven’t look into detail where the infinite loop occurs, but it seems like a hammer fix for the issue. The example mentioned in the test ((a + b) => (a - (-b)) => (a + b) => etc) makes me thinks that one of the two forms should be canonical and InstCombine should not make one of these two transforms. What do you think?
> >>>>>>
> >>>>>> I chose this way as it should guarantee to work for all cases, but you
> >>>>>> might be right in that something is wrong with pattern matching in
> >>>>>> InstCombine, see below.
> >>>>>>
> >>>>>> There is an implicit four step loop between InstCombiner::visitFAdd() and
> >>>>>> InstCombiner::visitFSub():
> >>>>>>
> >>>>>> 1. FAdd: Convert A to -A.
> >>>>>> 2. FSub: Convert -A to A; switch operands.
> >>>>>> 3. FAdd: Convert B to -B.
> >>>>>> 4. FSub: Convert -B to B; switch operands.
> >>>>>> 5. Go to step 1.
> >>>>>>
> >>>>>> Both functions try to do something about negative values, but they
> >>>>>> actually hang in case of positive arguments as well. I couldn't find
> >>>>>> any checks whether operands are negative, it seems to be "assumed".
> >>>>>> Maybe dyn_castFNegVal() used to perform the check, but it doesn't anymore.
> >>>>>>
> >>>>>> If I add `C->isNegative()` check to dyn_castFNegVal(), the issue
> >>>>>> disappears, but I'm not sure if it's the right place. Meaning of the
> >>>>>> comment there:
> >>>>>>
> >>>>>> // Constants can be considered to be negated values if they can be
> >>>>>> // folded.
> >>>>>> if (ConstantFP *C = dyn_cast<ConstantFP>(V))
> >>>>>> return ConstantExpr::getFNeg(C);
> >>>>>>
> >>>>>> is unclear to me. Does it suggest that the function doesn't care about
> >>>>>> sign of the value? In this case, checks for negative operands should be
> >>>>>> performed outside (in visitFAdd() and visitFSub() functions).
> >>>>>>
> >>>>>> Updated patches are attached (0000-recent-changes.diff contains latest
> >>>>>> changes only). There is nothing for InstCombine yet and a small new
> >>>>>> change (not counting test file) for LICM pass.
> >>>>>>
> >>>>>> Thanks,
> >>>>>> Sergey
-------------- next part --------------
>From 4ec30372f25a9be5ec5b3be9866c8b3258ec00d9 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Thu, 13 Nov 2014 16:54:23 +0200
Subject: [PATCH 01/13] Add flags and command-line switches for FPEnv
* Two flags for TargetOptions.
* Three command-line switches to enable flags separately or at the same
time.
---
include/llvm/CodeGen/CommandFlags.h | 19 +++++++++++++++++++
include/llvm/Target/TargetOptions.h | 17 ++++++++++++++++-
2 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/include/llvm/CodeGen/CommandFlags.h b/include/llvm/CodeGen/CommandFlags.h
index a58c2de..886f786 100644
--- a/include/llvm/CodeGen/CommandFlags.h
+++ b/include/llvm/CodeGen/CommandFlags.h
@@ -126,6 +126,21 @@ EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math",
cl::desc("Force codegen to assume rounding mode can change dynamically"),
cl::init(false));
+cl::opt<bool>
+EnableFPEnvAccessFPMath("enable-fpenv-access-fp-math",
+ cl::desc("Disable FP math optimizations that affect FP environment access"),
+ cl::init(false));
+
+cl::opt<bool>
+EnableExceptAccessFPMath("enable-except-access-fp-math",
+ cl::desc("Disable FP math optimizations that affect FP exceptions"),
+ cl::init(false));
+
+cl::opt<bool>
+EnableRoundAccessFPMath("enable-round-access-fp-math",
+ cl::desc("Disable FP math optimizations that affect FP rounding"),
+ cl::init(false));
+
cl::opt<llvm::FloatABI::ABIType>
FloatABIForCalls("float-abi",
cl::desc("Choose float ABI type"),
@@ -237,6 +252,10 @@ static inline TargetOptions InitTargetOptionsFromCodeGenFlags() {
Options.NoNaNsFPMath = EnableNoNaNsFPMath;
Options.HonorSignDependentRoundingFPMathOption =
EnableHonorSignDependentRoundingFPMath;
+ Options.AllowFPExceptAccess = EnableExceptAccessFPMath |
+ EnableFPEnvAccessFPMath;
+ Options.AllowFPRoundAccess = EnableRoundAccessFPMath |
+ EnableFPEnvAccessFPMath;
if (FloatABIForCalls != FloatABI::Default)
Options.FloatABIType = FloatABIForCalls;
Options.NoZerosInBSS = DontPlaceZerosInBSS;
diff --git a/include/llvm/Target/TargetOptions.h b/include/llvm/Target/TargetOptions.h
index 435a0fd..21f19c5 100644
--- a/include/llvm/Target/TargetOptions.h
+++ b/include/llvm/Target/TargetOptions.h
@@ -63,7 +63,8 @@ namespace llvm {
: PrintMachineCode(false), NoFramePointerElim(false),
NoFramePointerElimOverride(false),
LessPreciseFPMADOption(false), UnsafeFPMath(false),
- NoInfsFPMath(false), NoNaNsFPMath(false),
+ NoInfsFPMath(false), NoNaNsFPMath(false), AllowFPExceptAccess(false),
+ AllowFPRoundAccess(false),
HonorSignDependentRoundingFPMathOption(false),
NoZerosInBSS(false),
GuaranteedTailCallOpt(false),
@@ -121,6 +122,20 @@ namespace llvm {
/// assume the FP arithmetic arguments and results are never NaNs.
unsigned NoNaNsFPMath : 1;
+ /// AllowFPExceptAccess - This flag is enabled when the
+ /// -enable-except-access-fp-math or -enable-fpenv-access-fp-math flag is
+ /// specified on the command line. When this flag is off (the default), the
+ /// code generator is allowed to assume exceptions part of floating-point
+ /// environment is not accessed by the program.
+ unsigned AllowFPExceptAccess : 1;
+
+ /// AllowFPRoundAccess - This flag is enabled when the
+ /// -enable-round-access-fp-math or -enable-fpenv-access-fp-math flag is
+ /// specified on the command line. When this flag is off (the default), the
+ /// code generator is allowed to assume rounding part of floating-point
+ /// environment is not accessed by the program.
+ unsigned AllowFPRoundAccess : 1;
+
/// HonorSignDependentRoundingFPMath - This returns true when the
/// -enable-sign-dependent-rounding-fp-math is specified. If this returns
/// false (the default), the code generator is allowed to assume that the
--
2.3.5
-------------- next part --------------
>From 808f76d25fe576a1a0f6766c18ba1ac63857fa37 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Thu, 13 Nov 2014 16:06:06 +0200
Subject: [PATCH 02/13] Add FPEnv access flags to fast-math flags
Will be used to disable optimizations related to floating-point
operations which would affect runtime semantics (e.g. raising
floating-point exceptions).
---
docs/LangRef.rst | 9 ++++++++-
include/llvm/IR/Instruction.h | 16 ++++++++++++++++
include/llvm/IR/Operator.h | 30 +++++++++++++++++++++++++++++-
lib/AsmParser/LLLexer.cpp | 2 ++
lib/AsmParser/LLParser.h | 12 +++++++-----
lib/AsmParser/LLToken.h | 2 ++
lib/Bitcode/Reader/BitcodeReader.cpp | 4 ++++
lib/Bitcode/Writer/BitcodeWriter.cpp | 4 ++++
lib/IR/AsmWriter.cpp | 4 ++++
lib/IR/Instruction.cpp | 28 ++++++++++++++++++++++++++++
test/Assembler/fast-math-flags.ll | 8 ++++++++
11 files changed, 112 insertions(+), 7 deletions(-)
diff --git a/docs/LangRef.rst b/docs/LangRef.rst
index 1ee16f8..2e5cb69 100644
--- a/docs/LangRef.rst
+++ b/docs/LangRef.rst
@@ -1825,10 +1825,17 @@ otherwise unsafe floating point operations
Allow Reciprocal - Allow optimizations to use the reciprocal of an
argument rather than perform division.
+``kexc``
+ Keep Exceptions - Forbid optimizations to affect floating point exceptions
+ that can be thrown at runtime.
+
+``kround``
+ Keep Rounding - Forbid optimizations to assume any predefined rounding mode.
+
``fast``
Fast - Allow algebraically equivalent transformations that may
dramatically change results in floating point (e.g. reassociate). This
- flag implies all the others.
+ flag implies all the others except for the last two.
.. _uselistorder:
diff --git a/include/llvm/IR/Instruction.h b/include/llvm/IR/Instruction.h
index 2b9bc77..c44c58a 100644
--- a/include/llvm/IR/Instruction.h
+++ b/include/llvm/IR/Instruction.h
@@ -253,6 +253,16 @@ public:
/// this flag.
void setHasAllowReciprocal(bool B);
+ /// Set or clear the keep-exceptions flag on this instruction, which must be
+ /// an operator which supports this flag. See LangRef.html for the meaning of
+ /// this flag.
+ void setHasKeepExceptions(bool B);
+
+ /// Set or clear the keep-rounding flag on this instruction, which must be an
+ /// operator which supports this flag. See LangRef.html for the meaning of
+ /// this flag.
+ void setHasKeepRounding(bool B);
+
/// Convenience function for setting multiple fast-math flags on this
/// instruction, which must be an operator which supports these flags. See
/// LangRef.html for the meaning of these flags.
@@ -278,6 +288,12 @@ public:
/// Determine whether the allow-reciprocal flag is set.
bool hasAllowReciprocal() const;
+ /// Determine whether the keep-exceptions flag is set.
+ bool hasKeepExceptions() const;
+
+ /// Determine whether the keep-rounding flag is set.
+ bool hasKeepRounding() const;
+
/// Convenience function for getting all the fast-math flags, which must be an
/// operator which supports these flags. See LangRef.html for the meaning of
/// these flags.
diff --git a/include/llvm/IR/Operator.h b/include/llvm/IR/Operator.h
index 1b9102e..dd5e689 100644
--- a/include/llvm/IR/Operator.h
+++ b/include/llvm/IR/Operator.h
@@ -173,7 +173,9 @@ public:
NoNaNs = (1 << 1),
NoInfs = (1 << 2),
NoSignedZeros = (1 << 3),
- AllowReciprocal = (1 << 4)
+ AllowReciprocal = (1 << 4),
+ KeepExceptions = (1 << 5),
+ KeepRounding = (1 << 6)
};
FastMathFlags() : Flags(0)
@@ -191,6 +193,8 @@ public:
bool noSignedZeros() const { return 0 != (Flags & NoSignedZeros); }
bool allowReciprocal() const { return 0 != (Flags & AllowReciprocal); }
bool unsafeAlgebra() const { return 0 != (Flags & UnsafeAlgebra); }
+ bool keepExceptions() const { return 0 != (Flags & KeepExceptions); }
+ bool keepRounding()const { return 0 != (Flags & KeepRounding); }
/// Flag setters
void setNoNaNs() { Flags |= NoNaNs; }
@@ -204,6 +208,8 @@ public:
setNoSignedZeros();
setAllowReciprocal();
}
+ void setKeepExceptions() { Flags |= KeepExceptions; }
+ void setKeepRounding() { Flags |= KeepRounding; }
void operator&=(const FastMathFlags &OtherFlags) {
Flags &= OtherFlags.Flags;
@@ -250,6 +256,16 @@ private:
(SubclassOptionalData & ~FastMathFlags::AllowReciprocal) |
(B * FastMathFlags::AllowReciprocal);
}
+ void setHasKeepExceptions(bool B) {
+ SubclassOptionalData =
+ (SubclassOptionalData & ~FastMathFlags::KeepExceptions) |
+ (B * FastMathFlags::KeepExceptions);
+ }
+ void setHasKeepRounding(bool B) {
+ SubclassOptionalData =
+ (SubclassOptionalData & ~FastMathFlags::KeepRounding) |
+ (B * FastMathFlags::KeepRounding);
+ }
/// Convenience function for setting multiple fast-math flags.
/// FMF is a mask of the bits to set.
@@ -294,6 +310,18 @@ public:
return (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0;
}
+ /// Test whether this operation should not be optimized if its runtime
+ /// semantics regarding floating-point exceptions can't be preserved.
+ bool hasKeepExceptions() const {
+ return (SubclassOptionalData & FastMathFlags::KeepExceptions) != 0;
+ }
+
+ /// Test whether this operation should not be optimized if its runtime
+ /// semantics regarding floating-point rounding modes can't be preserved.
+ bool hasKeepRounding() const {
+ return (SubclassOptionalData & FastMathFlags::KeepRounding) != 0;
+ }
+
/// Convenience function for getting all the fast-math flags
FastMathFlags getFastMathFlags() const {
return FastMathFlags(SubclassOptionalData);
diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp
index a72f713..d508243 100644
--- a/lib/AsmParser/LLLexer.cpp
+++ b/lib/AsmParser/LLLexer.cpp
@@ -545,6 +545,8 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(ninf);
KEYWORD(nsz);
KEYWORD(arcp);
+ KEYWORD(kexc);
+ KEYWORD(kround);
KEYWORD(fast);
KEYWORD(nuw);
KEYWORD(nsw);
diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h
index a43a4b0..632d401 100644
--- a/lib/AsmParser/LLParser.h
+++ b/lib/AsmParser/LLParser.h
@@ -173,11 +173,13 @@ namespace llvm {
FastMathFlags FMF;
while (true)
switch (Lex.getKind()) {
- case lltok::kw_fast: FMF.setUnsafeAlgebra(); Lex.Lex(); continue;
- case lltok::kw_nnan: FMF.setNoNaNs(); Lex.Lex(); continue;
- case lltok::kw_ninf: FMF.setNoInfs(); Lex.Lex(); continue;
- case lltok::kw_nsz: FMF.setNoSignedZeros(); Lex.Lex(); continue;
- case lltok::kw_arcp: FMF.setAllowReciprocal(); Lex.Lex(); continue;
+ case lltok::kw_fast: FMF.setUnsafeAlgebra(); Lex.Lex(); continue;
+ case lltok::kw_nnan: FMF.setNoNaNs(); Lex.Lex(); continue;
+ case lltok::kw_ninf: FMF.setNoInfs(); Lex.Lex(); continue;
+ case lltok::kw_nsz: FMF.setNoSignedZeros(); Lex.Lex(); continue;
+ case lltok::kw_arcp: FMF.setAllowReciprocal(); Lex.Lex(); continue;
+ case lltok::kw_kexc: FMF.setKeepExceptions(); Lex.Lex(); continue;
+ case lltok::kw_kround: FMF.setKeepRounding(); Lex.Lex(); continue;
default: return FMF;
}
return FMF;
diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h
index 2bdc53b..122408d 100644
--- a/lib/AsmParser/LLToken.h
+++ b/lib/AsmParser/LLToken.h
@@ -66,6 +66,8 @@ namespace lltok {
kw_ninf,
kw_nsz,
kw_arcp,
+ kw_kexc,
+ kw_kround,
kw_fast,
kw_nuw,
kw_nsw,
diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp
index 6eef594..ec404c5 100644
--- a/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -3497,6 +3497,10 @@ std::error_code BitcodeReader::ParseFunctionBody(Function *F) {
FMF.setNoSignedZeros();
if (0 != (Record[OpNum] & FastMathFlags::AllowReciprocal))
FMF.setAllowReciprocal();
+ if (0 != (Record[OpNum] & FastMathFlags::KeepExceptions))
+ FMF.setKeepExceptions();
+ if (0 != (Record[OpNum] & FastMathFlags::KeepRounding))
+ FMF.setKeepRounding();
if (FMF.any())
I->setFastMathFlags(FMF);
}
diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp
index 3a539e1..bd24c24 100644
--- a/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -752,6 +752,10 @@ static uint64_t GetOptimizationFlags(const Value *V) {
Flags |= FastMathFlags::NoSignedZeros;
if (FPMO->hasAllowReciprocal())
Flags |= FastMathFlags::AllowReciprocal;
+ if (FPMO->hasKeepExceptions())
+ Flags |= FastMathFlags::KeepExceptions;
+ if (FPMO->hasKeepRounding())
+ Flags |= FastMathFlags::KeepRounding;
}
return Flags;
diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp
index 1089cb5..48ffd7b 100644
--- a/lib/IR/AsmWriter.cpp
+++ b/lib/IR/AsmWriter.cpp
@@ -1020,6 +1020,10 @@ static void WriteOptimizationInfo(raw_ostream &Out, const User *U) {
Out << " nsz";
if (FPO->hasAllowReciprocal())
Out << " arcp";
+ if (FPO->hasKeepExceptions())
+ Out << " kexc";
+ if (FPO->hasKeepRounding())
+ Out << " kround";
}
}
diff --git a/lib/IR/Instruction.cpp b/lib/IR/Instruction.cpp
index 57c143c..43fa285 100644
--- a/lib/IR/Instruction.cpp
+++ b/lib/IR/Instruction.cpp
@@ -124,6 +124,22 @@ void Instruction::setHasAllowReciprocal(bool B) {
cast<FPMathOperator>(this)->setHasAllowReciprocal(B);
}
+/// Set or clear the keep-exceptions flag on this instruction, which must be an
+/// operator which supports this flag. See LangRef.html for the meaning of this
+/// flag.
+void Instruction::setHasKeepExceptions(bool B) {
+ assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
+ cast<FPMathOperator>(this)->setHasKeepExceptions(B);
+}
+
+/// Set or clear the keep-rounding flag on this instruction, which must be an
+/// operator which supports this flag. See LangRef.html for the meaning of this
+/// flag.
+void Instruction::setHasKeepRounding(bool B) {
+ assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
+ cast<FPMathOperator>(this)->setHasKeepRounding(B);
+}
+
/// Convenience function for setting all the fast-math flags on this
/// instruction, which must be an operator which supports these flags. See
/// LangRef.html for the meaning of these flats.
@@ -167,6 +183,18 @@ bool Instruction::hasAllowReciprocal() const {
return cast<FPMathOperator>(this)->hasAllowReciprocal();
}
+/// Determine whether the keep-exceptions flag is set.
+bool Instruction::hasKeepExceptions() const {
+ assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
+ return cast<FPMathOperator>(this)->hasKeepExceptions();
+}
+
+/// Determine whether the keep-rounding flag is set.
+bool Instruction::hasKeepRounding() const {
+ assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
+ return cast<FPMathOperator>(this)->hasKeepRounding();
+}
+
/// Convenience function for getting all the fast-math flags, which must be an
/// operator which supports these flags. See LangRef.html for the meaning of
/// these flags.
diff --git a/test/Assembler/fast-math-flags.ll b/test/Assembler/fast-math-flags.ll
index f0d3ecc..4958c40 100644
--- a/test/Assembler/fast-math-flags.ll
+++ b/test/Assembler/fast-math-flags.ll
@@ -138,6 +138,14 @@ entry:
%e = frem nnan nsz float %x, %y
; CHECK: %e_vec = frem nnan <3 x float> %vec, %vec
%e_vec = frem nnan <3 x float> %vec, %vec
+; CHECK: %f = fmul fast float %x, %y
+ %f = fmul kexc kround fast float %x, %y
+; CHECK: %f_vec = frem fast <3 x float> %vec, %vec
+ %f_vec = frem kexc kround fast <3 x float> %vec, %vec
+; CHECK: %g = fmul kexc kround float %x, %y
+ %g = fmul kexc kround float %x, %y
+; CHECK: %g_vec = frem kexc kround <3 x float> %vec, %vec
+ %g_vec = frem kexc kround <3 x float> %vec, %vec
; CHECK: ret float %e
ret float %e
}
--
2.3.5
-------------- next part --------------
>From 1092a226e9722b40b6868c997c2c13c3b32dd5ae Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Thu, 13 Nov 2014 20:40:40 +0200
Subject: [PATCH 03/13] Consider FPEnv access in SelectionDAG
* Disable optimizations that erase floating-point exceptions at runtime
if application is allowed to access exception mask.
* Disable optimizations if application is allowed to access rounding and
result was rounded.
---
include/llvm/CodeGen/SelectionDAG.h | 5 ++
lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 31 +++++--
test/CodeGen/Generic/selectiondag-fenv.ll | 140 ++++++++++++++++++++++++++++++
3 files changed, 167 insertions(+), 9 deletions(-)
create mode 100644 test/CodeGen/Generic/selectiondag-fenv.ll
diff --git a/include/llvm/CodeGen/SelectionDAG.h b/include/llvm/CodeGen/SelectionDAG.h
index 89f9005..2cd8768 100644
--- a/include/llvm/CodeGen/SelectionDAG.h
+++ b/include/llvm/CodeGen/SelectionDAG.h
@@ -1264,6 +1264,11 @@ private:
SDNode *FindNodeOrInsertPos(const FoldingSetNodeID &ID, DebugLoc DL,
void *&InsertPos);
+ /// Checks whether it's safe to replace a floating-point operation with its
+ /// result. UnsafeOps is bit mask of unacceptable exceptions.
+ bool isSafeToOptimizeFPOp(APFloat::opStatus s,
+ APFloat::opStatus UnsafeOps) const;
+
/// List of non-single value types.
FoldingSet<SDVTListNode> VTListMap;
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index efd4bd9..95372ea 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -3577,7 +3577,6 @@ SDValue SelectionDAG::getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1,
}
// Constant fold FP operations.
- bool HasFPExceptions = TLI->hasFloatingPointExceptions();
ConstantFPSDNode *N1CFP = dyn_cast<ConstantFPSDNode>(N1.getNode());
ConstantFPSDNode *N2CFP = dyn_cast<ConstantFPSDNode>(N2.getNode());
if (N1CFP) {
@@ -3591,30 +3590,32 @@ SDValue SelectionDAG::getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1,
switch (Opcode) {
case ISD::FADD:
s = V1.add(V2, APFloat::rmNearestTiesToEven);
- if (!HasFPExceptions || s != APFloat::opInvalidOp)
+ if (isSafeToOptimizeFPOp(s, APFloat::opInvalidOp))
return getConstantFP(V1, DL, VT);
break;
case ISD::FSUB:
s = V1.subtract(V2, APFloat::rmNearestTiesToEven);
- if (!HasFPExceptions || s!=APFloat::opInvalidOp)
+ if (isSafeToOptimizeFPOp(s, APFloat::opInvalidOp))
return getConstantFP(V1, DL, VT);
break;
case ISD::FMUL:
s = V1.multiply(V2, APFloat::rmNearestTiesToEven);
- if (!HasFPExceptions || s!=APFloat::opInvalidOp)
+ if (isSafeToOptimizeFPOp(s, APFloat::opInvalidOp))
return getConstantFP(V1, DL, VT);
break;
case ISD::FDIV:
s = V1.divide(V2, APFloat::rmNearestTiesToEven);
- if (!HasFPExceptions || (s!=APFloat::opInvalidOp &&
- s!=APFloat::opDivByZero)) {
+ if (isSafeToOptimizeFPOp(s,
+ (APFloat::opStatus)(APFloat::opInvalidOp |
+ APFloat::opDivByZero))) {
return getConstantFP(V1, DL, VT);
}
break;
- case ISD::FREM :
+ case ISD::FREM:
s = V1.mod(V2, APFloat::rmNearestTiesToEven);
- if (!HasFPExceptions || (s!=APFloat::opInvalidOp &&
- s!=APFloat::opDivByZero)) {
+ if (isSafeToOptimizeFPOp(s,
+ (APFloat::opStatus)(APFloat::opInvalidOp |
+ APFloat::opDivByZero))) {
return getConstantFP(V1, DL, VT);
}
break;
@@ -3736,6 +3737,18 @@ SDValue SelectionDAG::getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1,
return SDValue(N, 0);
}
+bool SelectionDAG::isSafeToOptimizeFPOp(APFloat::opStatus s,
+ APFloat::opStatus UnsafeOps) const {
+ if (getTarget().Options.AllowFPRoundAccess && (s & APFloat::opInexact))
+ return false;
+
+ if (!TLI->hasFloatingPointExceptions())
+ return true;
+ if (getTarget().Options.AllowFPExceptAccess)
+ return s == APFloat::opOK;
+ return (s & UnsafeOps) == APFloat::opOK;
+}
+
SDValue SelectionDAG::getNode(unsigned Opcode, SDLoc DL, EVT VT,
SDValue N1, SDValue N2, SDValue N3) {
// Perform various simplifications.
diff --git a/test/CodeGen/Generic/selectiondag-fenv.ll b/test/CodeGen/Generic/selectiondag-fenv.ll
new file mode 100644
index 0000000..ed2e3f6
--- /dev/null
+++ b/test/CodeGen/Generic/selectiondag-fenv.ll
@@ -0,0 +1,140 @@
+; RUN: llc < %s -print-machineinstrs=expand-isel-pseudos -o /dev/null -enable-except-access-fp-math 2>&1 | FileCheck %s -check-prefix=CHECK -check-prefix=EXCEPT
+; RUN: llc < %s -print-machineinstrs=expand-isel-pseudos -o /dev/null -enable-round-access-fp-math 2>&1 | FileCheck %s -check-prefix=CHECK -check-prefix=ROUND
+
+; SelectionDAG should not fold floating-point operations that have constant
+; expression as their operands when FEnv access is enabled and such folding
+; leads to differences in observable effects at runtime.
+
+define double @do-not-fold-fadd-that-can-trap() {
+; CHECK-LABEL: do-not-fold-fadd-that-can-trap:
+; CHECK: cp#0: 1.000000e+308
+entry:
+ %val = fadd double 1.000000e+308, 1.000000e+308
+ ret double %val
+}
+
+define double @do-not-fold-fsub-that-can-trap() {
+; CHECK-LABEL: do-not-fold-fsub-that-can-trap:
+; CHECK: cp#0: 1.000000e-308
+; CHECK: cp#1: 1.000000e+308
+entry:
+ %val = fsub double 1.000000e-308, 1.000000e+308
+ ret double %val
+}
+
+define double @do-not-fold-fmul-that-can-trap() {
+; CHECK-LABEL: do-not-fold-fmul-that-can-trap:
+; CHECK: cp#0: 1.000000e+300
+entry:
+ %val = fmul double 1.000000e+300, 1.000000e+300
+ ret double %val
+}
+
+define double @do-not-fold-fdiv-that-can-trap() {
+; CHECK-LABEL: do-not-fold-fdiv-that-can-trap:
+; CHECK: cp#0: 1.000000e+300
+; CHECK: cp#1: 1.000000e-300
+entry:
+ %val = fdiv double 1.000000e+300, 1.000000e-300
+ ret double %val
+}
+
+define double @do-not-fold-frem-that-can-trap() {
+; CHECK-LABEL: do-not-fold-frem-that-can-trap:
+; CHECK: cp#0: 1.0
+entry:
+ %val = frem double 1.0, 0.0
+ ret double %val
+}
+
+define double @do-not-fold-fadd-because-of-rounding() {
+; CHECK-LABEL: do-not-fold-fadd-because-of-rounding:
+; EXCEPT: cp#0: 1.010000e-01
+; EXCEPT: cp#1: 9.300000e-01
+; ROUND: cp#0: 1.010000e-01
+; ROUND: cp#1: 9.300000e-01
+entry:
+ %val = fadd double 0.101, 0.93
+ ret double %val
+}
+
+define double @do-not-fold-fsub-because-of-rounding() {
+; CHECK-LABEL: do-not-fold-fsub-because-of-rounding:
+; EXCEPT: cp#0: 1.010000e-01
+; EXCEPT: cp#1: 9.300000e-01
+; ROUND: cp#0: 1.010000e-01
+; ROUND: cp#1: 9.300000e-01
+entry:
+ %val = fsub double 0.101, 0.93
+ ret double %val
+}
+
+define double @do-not-fold-fmul-because-of-rounding() {
+; CHECK-LABEL: do-not-fold-fmul-because-of-rounding:
+; EXCEPT: cp#0: 1.010000e-01
+; EXCEPT: cp#1: 9.300000e-01
+; ROUND: cp#0: 1.010000e-01
+; ROUND: cp#1: 9.300000e-01
+entry:
+ %val = fmul double 0.101, 0.93
+ ret double %val
+}
+
+define double @do-not-fold-fdiv-because-of-rounding() {
+; CHECK-LABEL: do-not-fold-fdiv-because-of-rounding:
+; EXCEPT: cp#0: 1.010000e-01
+; EXCEPT: cp#1: 9.300000e-01
+; ROUND: cp#0: 1.010000e-01
+; ROUND: cp#1: 9.300000e-01
+entry:
+ %val = fdiv double 0.101, 0.93
+ ret double %val
+}
+
+; "frem" instruction falls into the same category, but none of tried test-cases
+; could raised inexact exception.
+
+define double @fold-fadd-without-rounding() {
+; CHECK-LABEL: fold-fadd-without-rounding:
+; EXCEPT: cp#0: 2.0
+; ROUND: cp#0: 2.0
+entry:
+ %val = fadd double 1.0, 1.0
+ ret double %val
+}
+
+define double @fold-fsub-without-rounding() {
+; CHECK-LABEL: fold-fsub-without-rounding:
+; EXCEPT: cp#0: 1.0
+; ROUND: cp#0: 1.0
+entry:
+ %val = fsub double 3.0, 2.0
+ ret double %val
+}
+
+define double @fold-fmul-without-rounding() {
+; CHECK-LABEL: fold-fmul-without-rounding:
+; EXCEPT: cp#0: 6.0
+; ROUND: cp#0: 6.0
+entry:
+ %val = fmul double 2.0, 3.0
+ ret double %val
+}
+
+define double @fold-fdiv-without-rounding() {
+; CHECK-LABEL: fold-fdiv-without-rounding:
+; EXCEPT: cp#0: 2.0
+; ROUND: cp#0: 2.0
+entry:
+ %val = fdiv double 6.0, 3.0
+ ret double %val
+}
+
+define double @fold-frem-without-rounding() {
+; CHECK-LABEL: fold-frem-without-rounding:
+; EXCEPT: cp#0: 1.0
+; ROUND: cp#0: 1.0
+entry:
+ %val = frem double 7.0, 3.0
+ ret double %val
+}
--
2.3.5
-------------- next part --------------
>From abb5d94ede37b81dd856cb6466324a5d03bd6d9d Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Mon, 17 Nov 2014 23:10:29 +0200
Subject: [PATCH 04/13] Skip constant folding to preserve FPEnv
Consider floating point environment flags when constant folding
expressions.
---
include/llvm/Analysis/ValueTracking.h | 9 +++--
include/llvm/IR/Constants.h | 8 ++++-
lib/Analysis/ValueTracking.cpp | 25 +++++++++++++-
lib/IR/ConstantFold.cpp | 51 +++++++++++++++++++--------
lib/IR/ConstantFold.h | 3 +-
lib/IR/Constants.cpp | 65 +++++++++++++++++++++++++++++++++--
6 files changed, 138 insertions(+), 23 deletions(-)
diff --git a/include/llvm/Analysis/ValueTracking.h b/include/llvm/Analysis/ValueTracking.h
index 653821d..c395f43 100644
--- a/include/llvm/Analysis/ValueTracking.h
+++ b/include/llvm/Analysis/ValueTracking.h
@@ -229,8 +229,9 @@ namespace llvm {
const TargetLibraryInfo *TLI = nullptr);
/// isSafeToSpeculativelyExecute - Return true if the instruction does not
- /// have any effects besides calculating the result and does not have
- /// undefined behavior.
+ /// have any effects besides calculating the result (in a way that doesn't
+ /// lose floating-point exceptions or precision when requested via
+ /// corresponding flags) and does not have undefined behavior.
///
/// This method never returns true for an instruction that returns true for
/// mayHaveSideEffects; however, this method also does some other checks in
@@ -255,7 +256,9 @@ namespace llvm {
bool isSafeToSpeculativelyExecute(const Value *V,
const Instruction *CtxI = nullptr,
const DominatorTree *DT = nullptr,
- const TargetLibraryInfo *TLI = nullptr);
+ const TargetLibraryInfo *TLI = nullptr,
+ bool KeepExceptions = false,
+ bool KeepRounding = false);
/// isKnownNonNull - Return true if this pointer couldn't possibly be null by
/// its definition. This returns true for allocas, non-extern-weak globals
diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h
index e97bda5..352701f 100644
--- a/include/llvm/IR/Constants.h
+++ b/include/llvm/IR/Constants.h
@@ -1038,7 +1038,9 @@ public:
///
/// \param OnlyIfReducedTy see \a getWithOperands() docs.
static Constant *get(unsigned Opcode, Constant *C1, Constant *C2,
- unsigned Flags = 0, Type *OnlyIfReducedTy = nullptr);
+ unsigned Flags = 0, Type *OnlyIfReducedTy = nullptr,
+ bool KeepExceptions = false,
+ bool KeepRounding = false);
/// \brief Return an ICmp or FCmp comparison operator constant expression.
///
@@ -1164,6 +1166,10 @@ public:
return V->getValueID() == ConstantExprVal;
}
+ /// Evaluates floating point operation to examine it, does nothing for non-FP
+ /// operations. Returns false for unsupported values.
+ static bool getFPOpExceptions(const Value *V, APFloat::opStatus &S);
+
private:
// Shadow Value::setValueSubclassData with a private forwarding method so that
// subclasses cannot accidentally use it.
diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp
index a55712c..0fa0b42 100644
--- a/lib/Analysis/ValueTracking.cpp
+++ b/lib/Analysis/ValueTracking.cpp
@@ -3044,11 +3044,18 @@ bool llvm::isDereferenceablePointer(const Value *V, const DataLayout &DL,
bool llvm::isSafeToSpeculativelyExecute(const Value *V,
const Instruction *CtxI,
const DominatorTree *DT,
- const TargetLibraryInfo *TLI) {
+ const TargetLibraryInfo *TLI,
+ bool KeepExceptions,
+ bool KeepRounding) {
const Operator *Inst = dyn_cast<Operator>(V);
if (!Inst)
return false;
+ if (const FPMathOperator *MathOp = dyn_cast<FPMathOperator>(Inst)) {
+ KeepExceptions |= MathOp->hasKeepExceptions();
+ KeepRounding |= MathOp->hasKeepRounding();
+ }
+
for (unsigned i = 0, e = Inst->getNumOperands(); i != e; ++i)
if (Constant *C = dyn_cast<Constant>(Inst->getOperand(i)))
if (C->canTrap())
@@ -3057,6 +3064,22 @@ bool llvm::isSafeToSpeculativelyExecute(const Value *V,
switch (Inst->getOpcode()) {
default:
return true;
+ case Instruction::FMul:
+ case Instruction::FAdd:
+ case Instruction::FSub:
+ case Instruction::FDiv:
+ case Instruction::FRem:
+ if (KeepExceptions || KeepRounding) {
+ APFloat::opStatus S;
+ if (!ConstantExpr::getFPOpExceptions(Inst, S))
+ return false;
+
+ if (KeepExceptions && S != APFloat::opOK)
+ return false;
+ if (KeepRounding && (S & APFloat::opInexact))
+ return false;
+ }
+ return true;
case Instruction::UDiv:
case Instruction::URem: {
// x / y is undefined if y == 0.
diff --git a/lib/IR/ConstantFold.cpp b/lib/IR/ConstantFold.cpp
index 3f64c43..495b894 100644
--- a/lib/IR/ConstantFold.cpp
+++ b/lib/IR/ConstantFold.cpp
@@ -915,7 +915,9 @@ Constant *llvm::ConstantFoldInsertValueInstruction(Constant *Agg,
Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
- Constant *C1, Constant *C2) {
+ Constant *C1, Constant *C2,
+ bool KeepExceptions,
+ bool KeepRounding) {
// Handle UndefValue up front.
if (isa<UndefValue>(C1) || isa<UndefValue>(C2)) {
switch (Opcode) {
@@ -1099,7 +1101,8 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
} else if (isa<ConstantInt>(C1)) {
// If C1 is a ConstantInt and C2 is not, swap the operands.
if (Instruction::isCommutative(Opcode))
- return ConstantExpr::get(Opcode, C2, C1);
+ return ConstantExpr::get(Opcode, C2, C1, 0, nullptr, KeepExceptions,
+ KeepRounding);
}
// At this point we know neither constant is an UndefValue.
@@ -1171,23 +1174,39 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
APFloat C1V = CFP1->getValueAPF();
APFloat C2V = CFP2->getValueAPF();
APFloat C3V = C1V; // copy for modification
+ APFloat::opStatus S;
switch (Opcode) {
- default:
+ default:
break;
case Instruction::FAdd:
- (void)C3V.add(C2V, APFloat::rmNearestTiesToEven);
+ S = C3V.add(C2V, APFloat::rmNearestTiesToEven);
+ if ((KeepExceptions && S != APFloat::opOK) ||
+ (KeepRounding && (S & APFloat::opInexact)))
+ break;
return ConstantFP::get(C1->getContext(), C3V);
case Instruction::FSub:
- (void)C3V.subtract(C2V, APFloat::rmNearestTiesToEven);
+ S = C3V.subtract(C2V, APFloat::rmNearestTiesToEven);
+ if ((KeepExceptions && S != APFloat::opOK) ||
+ (KeepRounding && (S & APFloat::opInexact)))
+ break;
return ConstantFP::get(C1->getContext(), C3V);
case Instruction::FMul:
- (void)C3V.multiply(C2V, APFloat::rmNearestTiesToEven);
+ S = C3V.multiply(C2V, APFloat::rmNearestTiesToEven);
+ if ((KeepExceptions && S != APFloat::opOK) ||
+ (KeepRounding && (S & APFloat::opInexact)))
+ break;
return ConstantFP::get(C1->getContext(), C3V);
case Instruction::FDiv:
- (void)C3V.divide(C2V, APFloat::rmNearestTiesToEven);
+ S = C3V.divide(C2V, APFloat::rmNearestTiesToEven);
+ if ((KeepExceptions && S != APFloat::opOK) ||
+ (KeepRounding && (S & APFloat::opInexact)))
+ break;
return ConstantFP::get(C1->getContext(), C3V);
case Instruction::FRem:
- (void)C3V.mod(C2V, APFloat::rmNearestTiesToEven);
+ S = C3V.mod(C2V, APFloat::rmNearestTiesToEven);
+ if ((KeepExceptions && S != APFloat::opOK) ||
+ (KeepRounding && (S & APFloat::opInexact)))
+ break;
return ConstantFP::get(C1->getContext(), C3V);
}
}
@@ -1200,10 +1219,11 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
ConstantExpr::getExtractElement(C1, ConstantInt::get(Ty, i));
Constant *RHS =
ConstantExpr::getExtractElement(C2, ConstantInt::get(Ty, i));
-
- Result.push_back(ConstantExpr::get(Opcode, LHS, RHS));
+
+ Result.push_back(ConstantExpr::get(Opcode, LHS, RHS, 0, nullptr,
+ KeepExceptions, KeepRounding));
}
-
+
return ConstantVector::get(Result);
}
@@ -1215,15 +1235,18 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
// Given ((a + b) + c), if (b + c) folds to something interesting, return
// (a + (b + c)).
if (Instruction::isAssociative(Opcode) && CE1->getOpcode() == Opcode) {
- Constant *T = ConstantExpr::get(Opcode, CE1->getOperand(1), C2);
+ Constant *T = ConstantExpr::get(Opcode, CE1->getOperand(1), C2, 0,
+ nullptr, KeepExceptions, KeepRounding);
if (!isa<ConstantExpr>(T) || cast<ConstantExpr>(T)->getOpcode() != Opcode)
- return ConstantExpr::get(Opcode, CE1->getOperand(0), T);
+ return ConstantExpr::get(Opcode, CE1->getOperand(0), T, 0, nullptr,
+ KeepExceptions, KeepRounding);
}
} else if (isa<ConstantExpr>(C2)) {
// If C2 is a constant expr and C1 isn't, flop them around and fold the
// other way if possible.
if (Instruction::isCommutative(Opcode))
- return ConstantFoldBinaryInstruction(Opcode, C2, C1);
+ return ConstantFoldBinaryInstruction(Opcode, C2, C1, KeepExceptions,
+ KeepRounding);
}
// i1 can be simplified in many cases.
diff --git a/lib/IR/ConstantFold.h b/lib/IR/ConstantFold.h
index 42a9c6b..8e35aa0 100644
--- a/lib/IR/ConstantFold.h
+++ b/lib/IR/ConstantFold.h
@@ -44,7 +44,8 @@ namespace llvm {
Constant *ConstantFoldInsertValueInstruction(Constant *Agg, Constant *Val,
ArrayRef<unsigned> Idxs);
Constant *ConstantFoldBinaryInstruction(unsigned Opcode, Constant *V1,
- Constant *V2);
+ Constant *V2, bool KeepFPExceptions,
+ bool KeepFPRounding);
Constant *ConstantFoldCompareInstruction(unsigned short predicate,
Constant *C1, Constant *C2);
Constant *ConstantFoldGetElementPtr(Constant *C, bool inBounds,
diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp
index fb83ebb..1003ef3 100644
--- a/lib/IR/Constants.cpp
+++ b/lib/IR/Constants.cpp
@@ -316,8 +316,9 @@ static bool canTrapImpl(const Constant *C,
// ConstantExpr traps if any operands can trap.
for (unsigned i = 0, e = C->getNumOperands(); i != e; ++i) {
if (ConstantExpr *Op = dyn_cast<ConstantExpr>(CE->getOperand(i))) {
- if (NonTrappingOps.insert(Op).second && canTrapImpl(Op, NonTrappingOps))
+ if (NonTrappingOps.insert(Op).second && canTrapImpl(Op, NonTrappingOps)) {
return true;
+ }
}
}
@@ -1852,7 +1853,8 @@ Constant *ConstantExpr::getAddrSpaceCast(Constant *C, Type *DstTy,
}
Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2,
- unsigned Flags, Type *OnlyIfReducedTy) {
+ unsigned Flags, Type *OnlyIfReducedTy,
+ bool KeepExceptions, bool KeepRounding) {
// Check the operands for consistency first.
assert(Opcode >= Instruction::BinaryOpsBegin &&
Opcode < Instruction::BinaryOpsEnd &&
@@ -1918,8 +1920,11 @@ Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2,
}
#endif
- if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2))
+ if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2,
+ KeepExceptions,
+ KeepRounding)) {
return FC; // Fold a few common cases.
+ }
if (OnlyIfReducedTy == C1->getType())
return nullptr;
@@ -3050,3 +3055,57 @@ Instruction *ConstantExpr::getAsInstruction() {
return BO;
}
}
+
+bool ConstantExpr::getFPOpExceptions(const Value *V, APFloat::opStatus &S) {
+ unsigned Opcode;
+ const User *U;
+ if (const Operator *Op = dyn_cast<Operator>(V)) {
+ U = Op;
+ Opcode = Op->getOpcode();
+ } if (const ConstantExpr *C = dyn_cast<ConstantExpr>(V)) {
+ U = C;
+ Opcode = C->getOpcode();
+ } else {
+ return false;
+ }
+
+ switch (Opcode) {
+ default:
+ return true;
+ case Instruction::FMul:
+ case Instruction::FAdd:
+ case Instruction::FSub:
+ case Instruction::FDiv:
+ case Instruction::FRem: {
+ ConstantFP *LHSC = dyn_cast<ConstantFP>(U->getOperand(0));
+ ConstantFP *RHSC = dyn_cast<ConstantFP>(U->getOperand(1));
+
+ if (!LHSC || !RHSC) {
+ return false;
+ }
+
+ APFloat LHS = LHSC->getValueAPF();
+ APFloat RHS = LHSC->getValueAPF();
+
+ switch (Opcode) {
+ case Instruction::FMul:
+ S = LHS.multiply(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ case Instruction::FAdd:
+ S = LHS.add(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ case Instruction::FSub:
+ S = LHS.subtract(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ case Instruction::FDiv:
+ S = LHS.divide(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ case Instruction::FRem:
+ S = LHS.mod(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ }
+
+ return true;
+ }
+ }
+}
--
2.3.5
-------------- next part --------------
>From 13bc6d0b5970ca1e14c348070ad5bd9df8d167a2 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Wed, 26 Nov 2014 15:22:55 +0200
Subject: [PATCH 05/13] Teach IR builder and folders about new flags
---
include/llvm/Analysis/ConstantFolding.h | 8 +-
include/llvm/Analysis/TargetFolder.h | 37 ++++++---
include/llvm/IR/ConstantFolder.h | 44 +++++++----
include/llvm/IR/Constants.h | 24 ++++--
include/llvm/IR/IRBuilder.h | 30 +++++---
lib/Analysis/ConstantFolding.cpp | 40 +++++++---
lib/IR/ConstantFold.h | 4 +-
lib/IR/Constants.cpp | 36 ++++++---
test/Other/fpenv-constant-fold.ll | 130 ++++++++++++++++++++++++++++++++
9 files changed, 285 insertions(+), 68 deletions(-)
create mode 100644 test/Other/fpenv-constant-fold.ll
diff --git a/include/llvm/Analysis/ConstantFolding.h b/include/llvm/Analysis/ConstantFolding.h
index 541a210..b97e54f 100644
--- a/include/llvm/Analysis/ConstantFolding.h
+++ b/include/llvm/Analysis/ConstantFolding.h
@@ -44,7 +44,9 @@ namespace llvm {
/// result is returned, if not, null is returned.
Constant *
ConstantFoldConstantExpression(const ConstantExpr *CE, const DataLayout &DL,
- const TargetLibraryInfo *TLI = nullptr);
+ const TargetLibraryInfo *TLI = nullptr,
+ bool KeepExceptions = false,
+ bool KeepRounding = false);
/// ConstantFoldInstOperands - Attempt to constant fold an instruction with the
/// specified operands. If successful, the constant result is returned, if not,
@@ -55,7 +57,9 @@ namespace llvm {
Constant *ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
ArrayRef<Constant *> Ops,
const DataLayout &DL,
- const TargetLibraryInfo *TLI = nullptr);
+ const TargetLibraryInfo *TLI = nullptr,
+ bool KeepExceptions = false,
+ bool KeepRounding = false);
/// ConstantFoldCompareInstOperands - Attempt to constant fold a compare
/// instruction (icmp/fcmp) with the specified operands. If it fails, it
diff --git a/include/llvm/Analysis/TargetFolder.h b/include/llvm/Analysis/TargetFolder.h
index 12bf9fe..44f7edb 100644
--- a/include/llvm/Analysis/TargetFolder.h
+++ b/include/llvm/Analysis/TargetFolder.h
@@ -51,22 +51,31 @@ public:
bool HasNUW = false, bool HasNSW = false) const {
return Fold(ConstantExpr::getAdd(LHS, RHS, HasNUW, HasNSW));
}
- Constant *CreateFAdd(Constant *LHS, Constant *RHS) const {
- return Fold(ConstantExpr::getFAdd(LHS, RHS));
+ Constant *CreateFAdd(Constant *LHS, Constant *RHS,
+ bool KeepExceptions = false,
+ bool KeepRounding = false) const {
+ return Fold(ConstantExpr::getFAdd(LHS, RHS, KeepExceptions, KeepRounding));
}
Constant *CreateSub(Constant *LHS, Constant *RHS,
bool HasNUW = false, bool HasNSW = false) const {
return Fold(ConstantExpr::getSub(LHS, RHS, HasNUW, HasNSW));
}
- Constant *CreateFSub(Constant *LHS, Constant *RHS) const {
- return Fold(ConstantExpr::getFSub(LHS, RHS));
+ Constant *CreateFSub(Constant *LHS, Constant *RHS,
+ bool KeepExceptions = false,
+ bool KeepRounding = false) const {
+ return Fold(ConstantExpr::getFSub(LHS, RHS, KeepExceptions, KeepRounding));
}
Constant *CreateMul(Constant *LHS, Constant *RHS,
- bool HasNUW = false, bool HasNSW = false) const {
- return Fold(ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW));
+ bool HasNUW = false, bool HasNSW = false,
+ bool KeepExceptions = false,
+ bool KeepRounding = false) const {
+ return Fold(ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW,
+ KeepExceptions, KeepRounding));
}
- Constant *CreateFMul(Constant *LHS, Constant *RHS) const {
- return Fold(ConstantExpr::getFMul(LHS, RHS));
+ Constant *CreateFMul(Constant *LHS, Constant *RHS,
+ bool KeepExceptions = false,
+ bool KeepRounding = false) const {
+ return Fold(ConstantExpr::getFMul(LHS, RHS, KeepExceptions, KeepRounding));
}
Constant *CreateUDiv(Constant *LHS, Constant *RHS, bool isExact = false)const{
return Fold(ConstantExpr::getUDiv(LHS, RHS, isExact));
@@ -74,8 +83,10 @@ public:
Constant *CreateSDiv(Constant *LHS, Constant *RHS, bool isExact = false)const{
return Fold(ConstantExpr::getSDiv(LHS, RHS, isExact));
}
- Constant *CreateFDiv(Constant *LHS, Constant *RHS) const {
- return Fold(ConstantExpr::getFDiv(LHS, RHS));
+ Constant *CreateFDiv(Constant *LHS, Constant *RHS,
+ bool KeepExceptions = false,
+ bool KeepRounding = false) const {
+ return Fold(ConstantExpr::getFDiv(LHS, RHS, KeepExceptions, KeepRounding));
}
Constant *CreateURem(Constant *LHS, Constant *RHS) const {
return Fold(ConstantExpr::getURem(LHS, RHS));
@@ -83,8 +94,10 @@ public:
Constant *CreateSRem(Constant *LHS, Constant *RHS) const {
return Fold(ConstantExpr::getSRem(LHS, RHS));
}
- Constant *CreateFRem(Constant *LHS, Constant *RHS) const {
- return Fold(ConstantExpr::getFRem(LHS, RHS));
+ Constant *CreateFRem(Constant *LHS, Constant *RHS,
+ bool KeepExceptions = false,
+ bool KeepRounding = false) const {
+ return Fold(ConstantExpr::getFRem(LHS, RHS, KeepExceptions, KeepRounding));
}
Constant *CreateShl(Constant *LHS, Constant *RHS,
bool HasNUW = false, bool HasNSW = false) const {
diff --git a/include/llvm/IR/ConstantFolder.h b/include/llvm/IR/ConstantFolder.h
index fb6ca3b..d7f8e01 100644
--- a/include/llvm/IR/ConstantFolder.h
+++ b/include/llvm/IR/ConstantFolder.h
@@ -35,22 +35,31 @@ public:
bool HasNUW = false, bool HasNSW = false) const {
return ConstantExpr::getAdd(LHS, RHS, HasNUW, HasNSW);
}
- Constant *CreateFAdd(Constant *LHS, Constant *RHS) const {
- return ConstantExpr::getFAdd(LHS, RHS);
+ Constant *CreateFAdd(Constant *LHS, Constant *RHS,
+ bool KeepExceptions = false,
+ bool KeepRounding = false) const {
+ return ConstantExpr::getFAdd(LHS, RHS, KeepExceptions, KeepRounding);
}
Constant *CreateSub(Constant *LHS, Constant *RHS,
bool HasNUW = false, bool HasNSW = false) const {
return ConstantExpr::getSub(LHS, RHS, HasNUW, HasNSW);
}
- Constant *CreateFSub(Constant *LHS, Constant *RHS) const {
- return ConstantExpr::getFSub(LHS, RHS);
+ Constant *CreateFSub(Constant *LHS, Constant *RHS,
+ bool KeepExceptions = false,
+ bool KeepRounding = false) const {
+ return ConstantExpr::getFSub(LHS, RHS, KeepExceptions, KeepRounding);
}
Constant *CreateMul(Constant *LHS, Constant *RHS,
- bool HasNUW = false, bool HasNSW = false) const {
- return ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW);
+ bool HasNUW = false, bool HasNSW = false,
+ bool KeepExceptions = false,
+ bool KeepRounding = false) const {
+ return ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW, KeepExceptions,
+ KeepRounding);
}
- Constant *CreateFMul(Constant *LHS, Constant *RHS) const {
- return ConstantExpr::getFMul(LHS, RHS);
+ Constant *CreateFMul(Constant *LHS, Constant *RHS,
+ bool KeepExceptions = false,
+ bool KeepRounding = false) const {
+ return ConstantExpr::getFMul(LHS, RHS, KeepExceptions, KeepRounding);
}
Constant *CreateUDiv(Constant *LHS, Constant *RHS,
bool isExact = false) const {
@@ -60,8 +69,10 @@ public:
bool isExact = false) const {
return ConstantExpr::getSDiv(LHS, RHS, isExact);
}
- Constant *CreateFDiv(Constant *LHS, Constant *RHS) const {
- return ConstantExpr::getFDiv(LHS, RHS);
+ Constant *CreateFDiv(Constant *LHS, Constant *RHS,
+ bool KeepExceptions = false,
+ bool KeepRounding = false) const {
+ return ConstantExpr::getFDiv(LHS, RHS, KeepExceptions, KeepRounding);
}
Constant *CreateURem(Constant *LHS, Constant *RHS) const {
return ConstantExpr::getURem(LHS, RHS);
@@ -69,8 +80,10 @@ public:
Constant *CreateSRem(Constant *LHS, Constant *RHS) const {
return ConstantExpr::getSRem(LHS, RHS);
}
- Constant *CreateFRem(Constant *LHS, Constant *RHS) const {
- return ConstantExpr::getFRem(LHS, RHS);
+ Constant *CreateFRem(Constant *LHS, Constant *RHS,
+ bool KeepExceptions = false,
+ bool KeepRounding = false) const {
+ return ConstantExpr::getFRem(LHS, RHS, KeepExceptions, KeepRounding);
}
Constant *CreateShl(Constant *LHS, Constant *RHS,
bool HasNUW = false, bool HasNSW = false) const {
@@ -95,8 +108,11 @@ public:
}
Constant *CreateBinOp(Instruction::BinaryOps Opc,
- Constant *LHS, Constant *RHS) const {
- return ConstantExpr::get(Opc, LHS, RHS);
+ Constant *LHS, Constant *RHS,
+ bool KeepExceptions = false,
+ bool KeepRounding = false) const {
+ return ConstantExpr::get(Opc, LHS, RHS, 0, nullptr, KeepExceptions,
+ KeepRounding);
}
//===--------------------------------------------------------------------===//
diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h
index 352701f..f97a23d 100644
--- a/include/llvm/IR/Constants.h
+++ b/include/llvm/IR/Constants.h
@@ -863,19 +863,31 @@ public:
static Constant *getNot(Constant *C);
static Constant *getAdd(Constant *C1, Constant *C2,
bool HasNUW = false, bool HasNSW = false);
- static Constant *getFAdd(Constant *C1, Constant *C2);
+ static Constant *getFAdd(Constant *C1, Constant *C2,
+ bool KeepExceptions = false,
+ bool KeepRounding = false);
static Constant *getSub(Constant *C1, Constant *C2,
bool HasNUW = false, bool HasNSW = false);
- static Constant *getFSub(Constant *C1, Constant *C2);
+ static Constant *getFSub(Constant *C1, Constant *C2,
+ bool KeepExceptions = false,
+ bool KeepRounding = false);
static Constant *getMul(Constant *C1, Constant *C2,
- bool HasNUW = false, bool HasNSW = false);
- static Constant *getFMul(Constant *C1, Constant *C2);
+ bool HasNUW = false, bool HasNSW = false,
+ bool KeepExceptions = false,
+ bool KeepRounding = false);
+ static Constant *getFMul(Constant *C1, Constant *C2,
+ bool KeepExceptions = false,
+ bool KeepRounding = false);
static Constant *getUDiv(Constant *C1, Constant *C2, bool isExact = false);
static Constant *getSDiv(Constant *C1, Constant *C2, bool isExact = false);
- static Constant *getFDiv(Constant *C1, Constant *C2);
+ static Constant *getFDiv(Constant *C1, Constant *C2,
+ bool KeepExceptions = false,
+ bool KeepRounding = false);
static Constant *getURem(Constant *C1, Constant *C2);
static Constant *getSRem(Constant *C1, Constant *C2);
- static Constant *getFRem(Constant *C1, Constant *C2);
+ static Constant *getFRem(Constant *C1, Constant *C2,
+ bool KeepExceptions = false,
+ bool KeepRounding = false);
static Constant *getAnd(Constant *C1, Constant *C2);
static Constant *getOr(Constant *C1, Constant *C2);
static Constant *getXor(Constant *C1, Constant *C2);
diff --git a/include/llvm/IR/IRBuilder.h b/include/llvm/IR/IRBuilder.h
index adf6924..43089d4 100644
--- a/include/llvm/IR/IRBuilder.h
+++ b/include/llvm/IR/IRBuilder.h
@@ -733,10 +733,12 @@ public:
return CreateAdd(LHS, RHS, Name, true, false);
}
Value *CreateFAdd(Value *LHS, Value *RHS, const Twine &Name = "",
- MDNode *FPMathTag = nullptr) {
+ MDNode *FPMathTag = nullptr,
+ bool KeepExceptions = false, bool KeepRounding = false) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
- return Insert(Folder.CreateFAdd(LC, RC), Name);
+ return Insert(Folder.CreateFAdd(LC, RC, KeepExceptions, KeepRounding),
+ Name);
return Insert(AddFPMathAttributes(BinaryOperator::CreateFAdd(LHS, RHS),
FPMathTag, FMF), Name);
}
@@ -755,10 +757,12 @@ public:
return CreateSub(LHS, RHS, Name, true, false);
}
Value *CreateFSub(Value *LHS, Value *RHS, const Twine &Name = "",
- MDNode *FPMathTag = nullptr) {
+ MDNode *FPMathTag = nullptr,
+ bool KeepExceptions = false, bool KeepRounding = false) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
- return Insert(Folder.CreateFSub(LC, RC), Name);
+ return Insert(Folder.CreateFSub(LC, RC, KeepExceptions, KeepRounding),
+ Name);
return Insert(AddFPMathAttributes(BinaryOperator::CreateFSub(LHS, RHS),
FPMathTag, FMF), Name);
}
@@ -777,10 +781,12 @@ public:
return CreateMul(LHS, RHS, Name, true, false);
}
Value *CreateFMul(Value *LHS, Value *RHS, const Twine &Name = "",
- MDNode *FPMathTag = nullptr) {
+ MDNode *FPMathTag = nullptr,
+ bool KeepExceptions = false, bool KeepRounding = false) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
- return Insert(Folder.CreateFMul(LC, RC), Name);
+ return Insert(Folder.CreateFMul(LC, RC, KeepExceptions, KeepRounding),
+ Name);
return Insert(AddFPMathAttributes(BinaryOperator::CreateFMul(LHS, RHS),
FPMathTag, FMF), Name);
}
@@ -809,10 +815,12 @@ public:
return CreateSDiv(LHS, RHS, Name, true);
}
Value *CreateFDiv(Value *LHS, Value *RHS, const Twine &Name = "",
- MDNode *FPMathTag = nullptr) {
+ MDNode *FPMathTag = nullptr,
+ bool KeepExceptions = false, bool KeepRounding = false) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
- return Insert(Folder.CreateFDiv(LC, RC), Name);
+ return Insert(Folder.CreateFDiv(LC, RC, KeepExceptions, KeepRounding),
+ Name);
return Insert(AddFPMathAttributes(BinaryOperator::CreateFDiv(LHS, RHS),
FPMathTag, FMF), Name);
}
@@ -829,10 +837,12 @@ public:
return Insert(BinaryOperator::CreateSRem(LHS, RHS), Name);
}
Value *CreateFRem(Value *LHS, Value *RHS, const Twine &Name = "",
- MDNode *FPMathTag = nullptr) {
+ MDNode *FPMathTag = nullptr,
+ bool KeepExceptions = false, bool KeepRounding = false) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
- return Insert(Folder.CreateFRem(LC, RC), Name);
+ return Insert(Folder.CreateFRem(LC, RC, KeepExceptions, KeepRounding),
+ Name);
return Insert(AddFPMathAttributes(BinaryOperator::CreateFRem(LHS, RHS),
FPMathTag, FMF), Name);
}
diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp
index 2f4c6a9..197cffd 100644
--- a/lib/Analysis/ConstantFolding.cpp
+++ b/lib/Analysis/ConstantFolding.cpp
@@ -891,6 +891,14 @@ static Constant *SymbolicallyEvaluateGEP(Type *SrcTy, ArrayRef<Constant *> Ops,
/// and stores, which have no constant expression form.
Constant *llvm::ConstantFoldInstruction(Instruction *I, const DataLayout &DL,
const TargetLibraryInfo *TLI) {
+ bool KeepExceptions = false;
+ bool KeepRounding = false;
+
+ if (isa<FPMathOperator>(I)) {
+ KeepExceptions = I->hasKeepExceptions();
+ KeepRounding = I->hasKeepRounding();
+ }
+
// Handle PHI nodes quickly here...
if (PHINode *PN = dyn_cast<PHINode>(I)) {
Constant *CommonValue = nullptr;
@@ -908,7 +916,8 @@ Constant *llvm::ConstantFoldInstruction(Instruction *I, const DataLayout &DL,
return nullptr;
// Fold the PHI's operands.
if (ConstantExpr *NewC = dyn_cast<ConstantExpr>(C))
- C = ConstantFoldConstantExpression(NewC, DL, TLI);
+ C = ConstantFoldConstantExpression(NewC, DL, TLI,
+ KeepExceptions, KeepRounding);
// If the incoming value is a different constant to
// the one we saw previously, then give up.
if (CommonValue && C != CommonValue)
@@ -931,7 +940,8 @@ Constant *llvm::ConstantFoldInstruction(Instruction *I, const DataLayout &DL,
// Fold the Instruction's operands.
if (ConstantExpr *NewCE = dyn_cast<ConstantExpr>(Op))
- Op = ConstantFoldConstantExpression(NewCE, DL, TLI);
+ Op = ConstantFoldConstantExpression(NewCE, DL, TLI,
+ KeepExceptions, KeepRounding);
Ops.push_back(Op);
}
@@ -956,13 +966,15 @@ Constant *llvm::ConstantFoldInstruction(Instruction *I, const DataLayout &DL,
EVI->getIndices());
}
- return ConstantFoldInstOperands(I->getOpcode(), I->getType(), Ops, DL, TLI);
+ return ConstantFoldInstOperands(I->getOpcode(), I->getType(), Ops, DL, TLI,
+ KeepExceptions, KeepRounding);
}
static Constant *
ConstantFoldConstantExpressionImpl(const ConstantExpr *CE, const DataLayout &DL,
const TargetLibraryInfo *TLI,
- SmallPtrSetImpl<ConstantExpr *> &FoldedOps) {
+ SmallPtrSetImpl<ConstantExpr *> &FoldedOps,
+ bool KeepExceptions, bool KeepRounding) {
SmallVector<Constant *, 8> Ops;
for (User::const_op_iterator i = CE->op_begin(), e = CE->op_end(); i != e;
++i) {
@@ -971,7 +983,8 @@ ConstantFoldConstantExpressionImpl(const ConstantExpr *CE, const DataLayout &DL,
// a ConstantExpr, we don't have to process it again.
if (ConstantExpr *NewCE = dyn_cast<ConstantExpr>(NewC)) {
if (FoldedOps.insert(NewCE).second)
- NewC = ConstantFoldConstantExpressionImpl(NewCE, DL, TLI, FoldedOps);
+ NewC = ConstantFoldConstantExpressionImpl(NewCE, DL, TLI, FoldedOps,
+ KeepExceptions, KeepRounding);
}
Ops.push_back(NewC);
}
@@ -979,7 +992,8 @@ ConstantFoldConstantExpressionImpl(const ConstantExpr *CE, const DataLayout &DL,
if (CE->isCompare())
return ConstantFoldCompareInstOperands(CE->getPredicate(), Ops[0], Ops[1],
DL, TLI);
- return ConstantFoldInstOperands(CE->getOpcode(), CE->getType(), Ops, DL, TLI);
+ return ConstantFoldInstOperands(CE->getOpcode(), CE->getType(), Ops, DL, TLI,
+ KeepExceptions, KeepRounding);
}
/// Attempt to fold the constant expression
@@ -987,9 +1001,12 @@ ConstantFoldConstantExpressionImpl(const ConstantExpr *CE, const DataLayout &DL,
/// result is returned, if not, null is returned.
Constant *llvm::ConstantFoldConstantExpression(const ConstantExpr *CE,
const DataLayout &DL,
- const TargetLibraryInfo *TLI) {
+ const TargetLibraryInfo *TLI,
+ bool KeepExceptions,
+ bool KeepRounding) {
SmallPtrSet<ConstantExpr *, 4> FoldedOps;
- return ConstantFoldConstantExpressionImpl(CE, DL, TLI, FoldedOps);
+ return ConstantFoldConstantExpressionImpl(CE, DL, TLI, FoldedOps,
+ KeepExceptions, KeepRounding);
}
/// Attempt to constant fold an instruction with the
@@ -1005,7 +1022,9 @@ Constant *llvm::ConstantFoldConstantExpression(const ConstantExpr *CE,
Constant *llvm::ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
ArrayRef<Constant *> Ops,
const DataLayout &DL,
- const TargetLibraryInfo *TLI) {
+ const TargetLibraryInfo *TLI,
+ bool KeepExceptions,
+ bool KeepRounding) {
// Handle easy binops first.
if (Instruction::isBinaryOp(Opcode)) {
if (isa<ConstantExpr>(Ops[0]) || isa<ConstantExpr>(Ops[1])) {
@@ -1013,7 +1032,8 @@ Constant *llvm::ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
return C;
}
- return ConstantExpr::get(Opcode, Ops[0], Ops[1]);
+ return ConstantExpr::get(Opcode, Ops[0], Ops[1], 0, nullptr,
+ KeepExceptions, KeepRounding);
}
switch (Opcode) {
diff --git a/lib/IR/ConstantFold.h b/lib/IR/ConstantFold.h
index 8e35aa0..f635ce1 100644
--- a/lib/IR/ConstantFold.h
+++ b/lib/IR/ConstantFold.h
@@ -44,8 +44,8 @@ namespace llvm {
Constant *ConstantFoldInsertValueInstruction(Constant *Agg, Constant *Val,
ArrayRef<unsigned> Idxs);
Constant *ConstantFoldBinaryInstruction(unsigned Opcode, Constant *V1,
- Constant *V2, bool KeepFPExceptions,
- bool KeepFPRounding);
+ Constant *V2, bool KeepExceptions,
+ bool KeepRounding);
Constant *ConstantFoldCompareInstruction(unsigned short predicate,
Constant *C1, Constant *C2);
Constant *ConstantFoldGetElementPtr(Constant *C, bool inBounds,
diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp
index 1003ef3..3d18cfd 100644
--- a/lib/IR/Constants.cpp
+++ b/lib/IR/Constants.cpp
@@ -2253,8 +2253,10 @@ Constant *ConstantExpr::getAdd(Constant *C1, Constant *C2,
return get(Instruction::Add, C1, C2, Flags);
}
-Constant *ConstantExpr::getFAdd(Constant *C1, Constant *C2) {
- return get(Instruction::FAdd, C1, C2);
+Constant *ConstantExpr::getFAdd(Constant *C1, Constant *C2,
+ bool KeepExceptions, bool KeepRounding) {
+ return get(Instruction::FAdd, C1, C2, 0, nullptr, KeepExceptions,
+ KeepRounding);
}
Constant *ConstantExpr::getSub(Constant *C1, Constant *C2,
@@ -2264,19 +2266,25 @@ Constant *ConstantExpr::getSub(Constant *C1, Constant *C2,
return get(Instruction::Sub, C1, C2, Flags);
}
-Constant *ConstantExpr::getFSub(Constant *C1, Constant *C2) {
- return get(Instruction::FSub, C1, C2);
+Constant *ConstantExpr::getFSub(Constant *C1, Constant *C2,
+ bool KeepExceptions, bool KeepRounding) {
+ return get(Instruction::FSub, C1, C2, 0, nullptr, KeepExceptions,
+ KeepRounding);
}
Constant *ConstantExpr::getMul(Constant *C1, Constant *C2,
- bool HasNUW, bool HasNSW) {
+ bool HasNUW, bool HasNSW,
+ bool KeepExceptions, bool KeepRounding) {
unsigned Flags = (HasNUW ? OverflowingBinaryOperator::NoUnsignedWrap : 0) |
(HasNSW ? OverflowingBinaryOperator::NoSignedWrap : 0);
- return get(Instruction::Mul, C1, C2, Flags);
+ return get(Instruction::Mul, C1, C2, Flags, nullptr, KeepExceptions,
+ KeepRounding);
}
-Constant *ConstantExpr::getFMul(Constant *C1, Constant *C2) {
- return get(Instruction::FMul, C1, C2);
+Constant *ConstantExpr::getFMul(Constant *C1, Constant *C2,
+ bool KeepExceptions, bool KeepRounding) {
+ return get(Instruction::FMul, C1, C2, 0, nullptr, KeepExceptions,
+ KeepRounding);
}
Constant *ConstantExpr::getUDiv(Constant *C1, Constant *C2, bool isExact) {
@@ -2289,8 +2297,10 @@ Constant *ConstantExpr::getSDiv(Constant *C1, Constant *C2, bool isExact) {
isExact ? PossiblyExactOperator::IsExact : 0);
}
-Constant *ConstantExpr::getFDiv(Constant *C1, Constant *C2) {
- return get(Instruction::FDiv, C1, C2);
+Constant *ConstantExpr::getFDiv(Constant *C1, Constant *C2,
+ bool KeepExceptions, bool KeepRounding) {
+ return get(Instruction::FDiv, C1, C2, 0, nullptr, KeepExceptions,
+ KeepRounding);
}
Constant *ConstantExpr::getURem(Constant *C1, Constant *C2) {
@@ -2301,8 +2311,10 @@ Constant *ConstantExpr::getSRem(Constant *C1, Constant *C2) {
return get(Instruction::SRem, C1, C2);
}
-Constant *ConstantExpr::getFRem(Constant *C1, Constant *C2) {
- return get(Instruction::FRem, C1, C2);
+Constant *ConstantExpr::getFRem(Constant *C1, Constant *C2,
+ bool KeepExceptions, bool KeepRounding) {
+ return get(Instruction::FRem, C1, C2, 0, nullptr, KeepExceptions,
+ KeepRounding);
}
Constant *ConstantExpr::getAnd(Constant *C1, Constant *C2) {
diff --git a/test/Other/fpenv-constant-fold.ll b/test/Other/fpenv-constant-fold.ll
new file mode 100644
index 0000000..01dbfa0
--- /dev/null
+++ b/test/Other/fpenv-constant-fold.ll
@@ -0,0 +1,130 @@
+; InstCombine is used just for its calls to constant folder.
+; RUN: opt -S -instcombine -o - < %s | FileCheck %s
+
+; Target independent constant folder should not fold floating-point operations
+; that have constant expression as their operands when FEnv access is requested
+; and such folding leads to differences in observable effects at runtime.
+
+define double @do-not-fold-fadd-that-can-trap() {
+; CHECK-LABEL: @do-not-fold-fadd-that-can-trap
+; CHECK: fadd
+entry:
+ %val = fadd kexc double 1.000000e+308, 1.000000e+308
+ ret double %val
+}
+
+define double @do-not-fold-fsub-that-can-trap() {
+; CHECK-LABEL: @do-not-fold-fsub-that-can-trap
+; CHECK: fsub
+entry:
+ %val = fsub kexc double 1.000000e-308, 1.000000e+308
+ ret double %val
+}
+
+define double @do-not-fold-fmul-that-can-trap() {
+; CHECK-LABEL: @do-not-fold-fmul-that-can-trap
+; CHECK: fmul
+entry:
+ %val = fmul kexc double 1.000000e+300, 1.000000e+300
+ ret double %val
+}
+
+define double @do-not-fold-fdiv-that-can-trap() {
+; CHECK-LABEL: @do-not-fold-fdiv-that-can-trap
+; CHECK: fdiv
+entry:
+ %val = fdiv kexc double 1.000000e+300, 1.000000e-300
+ ret double %val
+}
+
+define double @do-not-fold-frem-that-can-trap() {
+; CHECK-LABEL: @do-not-fold-frem-that-can-trap
+; CHECK: frem
+entry:
+ %val = frem kexc double 1.000000e+300, 1.000000e-300
+ ret double %val
+}
+
+define double @do-not-fold-fadd-because-of-rounding() {
+; CHECK-LABEL: @do-not-fold-fadd-because-of-rounding
+; CHECK: fadd
+entry:
+ %val = fadd kround double 0.101, 0.93
+ ret double %val
+}
+
+define double @do-not-fold-fsub-because-of-rounding() {
+; CHECK-LABEL: @do-not-fold-fsub-because-of-rounding
+; CHECK: fsub
+entry:
+ %val = fsub kround double 0.101, 0.93
+ ret double %val
+}
+
+define double @do-not-fold-fmul-because-of-rounding() {
+; CHECK-LABEL: @do-not-fold-fmul-because-of-rounding
+; CHECK: fmul
+entry:
+ %val = fmul kround double 0.101, 0.93
+ ret double %val
+}
+
+define double @do-not-fold-fdiv-because-of-rounding() {
+; CHECK-LABEL: @do-not-fold-fdiv-because-of-rounding
+; CHECK: fdiv
+entry:
+ %val = fdiv kround double 0.101, 0.93
+ ret double %val
+}
+
+; "frem" instruction falls into the same category, but none of tried test-cases
+; could raised inexact exception.
+
+define double @fold-fadd-that-cant-trap() {
+; CHECK-LABEL: @fold-fadd-that-cant-trap
+; CHECK-NOT: fadd
+entry:
+ %val = fadd kexc kround double 1.0, 1.0
+ ret double %val
+}
+
+define double @fold-fsub-that-cant-trap() {
+; CHECK-LABEL: @fold-fsub-that-cant-trap
+; CHECK-NOT: fsub
+entry:
+ %val = fsub kexc kround double 1.0, 1.0
+ ret double %val
+}
+
+define double @fold-fmul-that-cant-trap() {
+; CHECK-LABEL: @fold-fmul-that-cant-trap
+; CHECK-NOT: fmul
+entry:
+ %val = fmul kexc kround double 1.0, 1.0
+ ret double %val
+}
+
+define double @fold-fdiv-that-cant-trap() {
+; CHECK-LABEL: @fold-fdiv-that-cant-trap
+; CHECK-NOT: fdiv
+entry:
+ %val = fdiv kexc kround double 1.0, 1.0
+ ret double %val
+}
+
+define double @fold-frem-that-cant-trap() {
+; CHECK-LABEL: @fold-frem-that-cant-trap
+; CHECK-NOT: frem
+entry:
+ %val = frem kexc kround double 1.0, 1.0
+ ret double %val
+}
+
+define double @correcly-handle-nested-expressions() {
+; CHECK-LABEL: @correcly-handle-nested-expressions
+; CHECK: fmul
+entry:
+ %val1 = fmul kexc double 1.000000e+300, 1.000000e+300
+ %val2 = fdiv kexc double %val1, 1.000000e+300
+ ret double %val2
+}
--
2.3.5
-------------- next part --------------
>From e489145cf4dfc40f761cdc466cd801b6fe7879cd Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Wed, 26 Nov 2014 19:50:50 +0200
Subject: [PATCH 06/13] Do not fold constants on reading in IR asm/bitcode
---
lib/AsmParser/LLParser.cpp | 3 ++-
lib/Bitcode/Reader/BitcodeReader.cpp | 2 +-
test/Assembler/do-not-fold-fp-consts.ll | 36 +++++++++++++++++++++++++++++++++
3 files changed, 39 insertions(+), 2 deletions(-)
create mode 100644 test/Assembler/do-not-fold-fp-consts.ll
diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp
index d3c8ffd..de1a1bc 100644
--- a/lib/AsmParser/LLParser.cpp
+++ b/lib/AsmParser/LLParser.cpp
@@ -2783,7 +2783,8 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) {
if (NUW) Flags |= OverflowingBinaryOperator::NoUnsignedWrap;
if (NSW) Flags |= OverflowingBinaryOperator::NoSignedWrap;
if (Exact) Flags |= PossiblyExactOperator::IsExact;
- Constant *C = ConstantExpr::get(Opc, Val0, Val1, Flags);
+ Constant *C = ConstantExpr::get(Opc, Val0, Val1, Flags, nullptr, true,
+ true);
ID.ConstantVal = C;
ID.Kind = ValID::t_Constant;
return false;
diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp
index ec404c5..77c01c3 100644
--- a/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2316,7 +2316,7 @@ std::error_code BitcodeReader::ParseConstants() {
Flags |= SDivOperator::IsExact;
}
}
- V = ConstantExpr::get(Opc, LHS, RHS, Flags);
+ V = ConstantExpr::get(Opc, LHS, RHS, Flags, nullptr, true, true);
}
break;
}
diff --git a/test/Assembler/do-not-fold-fp-consts.ll b/test/Assembler/do-not-fold-fp-consts.ll
new file mode 100644
index 0000000..6b2ddcb
--- /dev/null
+++ b/test/Assembler/do-not-fold-fp-consts.ll
@@ -0,0 +1,36 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+
+define double @do-not-fold-fadd() {
+; CHECK-LABEL: @do-not-fold-fadd
+; CHECK: fadd
+entry:
+ ret double fadd (double 1.000000e+308, double 1.000000e+308)
+}
+
+define double @do-not-fold-fsub() {
+; CHECK-LABEL: @do-not-fold-fsub
+; CHECK: fsub
+entry:
+ ret double fsub (double 1.000000e-308, double 1.000000e+308)
+}
+
+define double @do-not-fold-fmul() {
+; CHECK-LABEL: @do-not-fold-fmul
+; CHECK: fmul
+entry:
+ ret double fmul (double 1.000000e+300, double 1.000000e+300)
+}
+
+define double @do-not-fold-fdiv() {
+; CHECK-LABEL: @do-not-fold-fdiv
+; CHECK: fdiv
+entry:
+ ret double fdiv (double 1.000000e+300, double 1.000000e-300)
+}
+
+define double @do-not-fold-frem() {
+; CHECK-LABEL: @do-not-fold-frem
+; CHECK: frem
+entry:
+ ret double frem (double 1.000000e+300, double 1.000000e-300)
+}
--
2.3.5
-------------- next part --------------
>From db43c926abc925cfbf322817239320654ed245b4 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 28 Nov 2014 12:58:45 +0200
Subject: [PATCH 07/13] Prevent undesired folding by InstSimplify
---
lib/Analysis/InstructionSimplify.cpp | 9 ++++--
test/Transforms/InstSimplify/fast-math.ll | 48 +++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp
index 097b99e..d754caa 100644
--- a/lib/Analysis/InstructionSimplify.cpp
+++ b/lib/Analysis/InstructionSimplify.cpp
@@ -790,7 +790,8 @@ static Value *SimplifyFAddInst(Value *Op0, Value *Op1, FastMathFlags FMF,
if (Constant *CRHS = dyn_cast<Constant>(Op1)) {
Constant *Ops[] = { CLHS, CRHS };
return ConstantFoldInstOperands(Instruction::FAdd, CLHS->getType(),
- Ops, Q.DL, Q.TLI);
+ Ops, Q.DL, Q.TLI,
+ FMF.keepExceptions(), FMF.keepRounding());
}
// Canonicalize the constant to the RHS.
@@ -832,7 +833,8 @@ static Value *SimplifyFSubInst(Value *Op0, Value *Op1, FastMathFlags FMF,
if (Constant *CRHS = dyn_cast<Constant>(Op1)) {
Constant *Ops[] = { CLHS, CRHS };
return ConstantFoldInstOperands(Instruction::FSub, CLHS->getType(),
- Ops, Q.DL, Q.TLI);
+ Ops, Q.DL, Q.TLI,
+ FMF.keepExceptions(), FMF.keepRounding());
}
}
@@ -870,7 +872,8 @@ static Value *SimplifyFMulInst(Value *Op0, Value *Op1,
if (Constant *CRHS = dyn_cast<Constant>(Op1)) {
Constant *Ops[] = { CLHS, CRHS };
return ConstantFoldInstOperands(Instruction::FMul, CLHS->getType(),
- Ops, Q.DL, Q.TLI);
+ Ops, Q.DL, Q.TLI,
+ FMF.keepExceptions(), FMF.keepRounding());
}
// Canonicalize the constant to the RHS.
diff --git a/test/Transforms/InstSimplify/fast-math.ll b/test/Transforms/InstSimplify/fast-math.ll
index e7fb14d..e7bbb49 100644
--- a/test/Transforms/InstSimplify/fast-math.ll
+++ b/test/Transforms/InstSimplify/fast-math.ll
@@ -114,3 +114,51 @@ define double @fdiv_zero_by_x(double %X) {
ret double %r
; CHECK: ret double 0
}
+
+; CHECK-LABEL: @nofold_fadd_kexc(
+define double @nofold_fadd_kexc() {
+; CHECK: fadd
+entry:
+ %val = fadd kexc double 1.000000e+308, 1.000000e+308
+ ret double %val
+}
+
+; CHECK-LABEL: @nofold_fsub_kexc(
+define double @nofold_fsub_kexc() {
+; CHECK: fsub
+entry:
+ %val = fsub kexc double 1.000000e-308, 1.000000e+308
+ ret double %val
+}
+
+; CHECK-LABEL: @nofold_fmul_kexc(
+define double @nofold_fmul_kexc() {
+; CHECK: fmul
+entry:
+ %val = fmul kexc double 1.000000e+300, 1.000000e+300
+ ret double %val
+}
+
+; CHECK-LABEL: @nofold_fadd_kround(
+define double @nofold_fadd_kround() {
+; CHECK: fadd
+entry:
+ %val = fadd kround double 1.000000e+308, 1.000000e+308
+ ret double %val
+}
+
+; CHECK-LABEL: @nofold_fsub_kround(
+define double @nofold_fsub_kround() {
+; CHECK: fsub
+entry:
+ %val = fsub kround double 1.000000e-308, 1.000000e+308
+ ret double %val
+}
+
+; CHECK-LABEL: @nofold_fmul_kround(
+define double @nofold_fmul_kround() {
+; CHECK: fmul
+entry:
+ %val = fmul kround double 1.000000e+300, 1.000000e+300
+ ret double %val
+}
--
2.3.5
-------------- next part --------------
>From 59b81b17eeac60e021c70ff5bc66b271c1d467e3 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 28 Nov 2014 15:53:44 +0200
Subject: [PATCH 08/13] Do not simplify expressions with FPEnv access
ConstantExpression can't store these flags, which can lead to
going against them.
---
include/llvm/IR/Constants.h | 4 ++--
lib/Analysis/ConstantFolding.cpp | 2 +-
lib/IR/Constants.cpp | 8 +++++++-
test/Transforms/EarlyCSE/fpenv.ll | 24 ++++++++++++++++++++++++
4 files changed, 34 insertions(+), 4 deletions(-)
create mode 100644 test/Transforms/EarlyCSE/fpenv.ll
diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h
index f97a23d..db487d2 100644
--- a/include/llvm/IR/Constants.h
+++ b/include/llvm/IR/Constants.h
@@ -1051,8 +1051,8 @@ public:
/// \param OnlyIfReducedTy see \a getWithOperands() docs.
static Constant *get(unsigned Opcode, Constant *C1, Constant *C2,
unsigned Flags = 0, Type *OnlyIfReducedTy = nullptr,
- bool KeepExceptions = false,
- bool KeepRounding = false);
+ bool KeepExceptions = false, bool KeepRounding = false,
+ bool Strict = false);
/// \brief Return an ICmp or FCmp comparison operator constant expression.
///
diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp
index 197cffd..7063553 100644
--- a/lib/Analysis/ConstantFolding.cpp
+++ b/lib/Analysis/ConstantFolding.cpp
@@ -1033,7 +1033,7 @@ Constant *llvm::ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
}
return ConstantExpr::get(Opcode, Ops[0], Ops[1], 0, nullptr,
- KeepExceptions, KeepRounding);
+ KeepExceptions, KeepRounding, /* Strict = */ true);
}
switch (Opcode) {
diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp
index 3d18cfd..4277f7d 100644
--- a/lib/IR/Constants.cpp
+++ b/lib/IR/Constants.cpp
@@ -1854,7 +1854,8 @@ Constant *ConstantExpr::getAddrSpaceCast(Constant *C, Type *DstTy,
Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2,
unsigned Flags, Type *OnlyIfReducedTy,
- bool KeepExceptions, bool KeepRounding) {
+ bool KeepExceptions, bool KeepRounding,
+ bool Strict) {
// Check the operands for consistency first.
assert(Opcode >= Instruction::BinaryOpsBegin &&
Opcode < Instruction::BinaryOpsEnd &&
@@ -1929,6 +1930,11 @@ Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2,
if (OnlyIfReducedTy == C1->getType())
return nullptr;
+ // ConstantExpression can't store these flags, which can lead to going against
+ // them.
+ if (Strict && (KeepExceptions || KeepRounding))
+ return nullptr;
+
Constant *ArgVec[] = { C1, C2 };
ConstantExprKeyType Key(Opcode, ArgVec, 0, Flags);
diff --git a/test/Transforms/EarlyCSE/fpenv.ll b/test/Transforms/EarlyCSE/fpenv.ll
new file mode 100644
index 0000000..aba632c
--- /dev/null
+++ b/test/Transforms/EarlyCSE/fpenv.ll
@@ -0,0 +1,24 @@
+; %val.true and %val.false should not be moved inside phi-node as constant
+; expressions as such transformation looses fast-math flags.
+; RUN: opt < %s -S -early-cse | FileCheck %s
+
+define double @do-not-turn-into-constexpr(double %x) {
+; CHECK-LABEL: @do-not-turn-into-constexpr(
+; CHECK: %val.true = fmul
+; CHECK: %val.false = fmul
+entry:
+ %cmp = fcmp oeq double %x, 0.000000e+00
+ br i1 %cmp, label %cond.true, label %cond.false
+
+cond.true: ; preds = %entry
+ %val.true = fmul kexc double 1.000000e+300, 1.000000e+300
+ br label %cond.end
+
+cond.false: ; preds = %entry
+ %val.false = fmul kexc double 1.000000e-300, 1.000000e-300
+ br label %cond.end
+
+cond.end: ; preds = %cond.false, %cond.true
+ %cond = phi double [ %val.true, %cond.true ], [ %val.false, %cond.false ]
+ ret double %cond
+}
--
2.3.5
-------------- next part --------------
>From 51a8815d3b8e3bbdd9402e6736f6fbb34a169aac Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 12 Dec 2014 16:35:01 +0200
Subject: [PATCH 09/13] Make Strict flag available for more clients
---
include/llvm/Analysis/TargetFolder.h | 35 +++++++++++++++++++++++------------
include/llvm/IR/ConstantFolder.h | 35 +++++++++++++++++++++++------------
include/llvm/IR/Constants.h | 18 ++++++++++++------
lib/IR/Constants.cpp | 30 ++++++++++++++++++------------
4 files changed, 76 insertions(+), 42 deletions(-)
diff --git a/include/llvm/Analysis/TargetFolder.h b/include/llvm/Analysis/TargetFolder.h
index 44f7edb..f2188f3 100644
--- a/include/llvm/Analysis/TargetFolder.h
+++ b/include/llvm/Analysis/TargetFolder.h
@@ -53,8 +53,10 @@ public:
}
Constant *CreateFAdd(Constant *LHS, Constant *RHS,
bool KeepExceptions = false,
- bool KeepRounding = false) const {
- return Fold(ConstantExpr::getFAdd(LHS, RHS, KeepExceptions, KeepRounding));
+ bool KeepRounding = false,
+ bool Strict = false) const {
+ return Fold(ConstantExpr::getFAdd(LHS, RHS, KeepExceptions, KeepRounding,
+ Strict));
}
Constant *CreateSub(Constant *LHS, Constant *RHS,
bool HasNUW = false, bool HasNSW = false) const {
@@ -62,20 +64,25 @@ public:
}
Constant *CreateFSub(Constant *LHS, Constant *RHS,
bool KeepExceptions = false,
- bool KeepRounding = false) const {
- return Fold(ConstantExpr::getFSub(LHS, RHS, KeepExceptions, KeepRounding));
+ bool KeepRounding = false,
+ bool Strict = false) const {
+ return Fold(ConstantExpr::getFSub(LHS, RHS, KeepExceptions, KeepRounding,
+ Strict));
}
Constant *CreateMul(Constant *LHS, Constant *RHS,
bool HasNUW = false, bool HasNSW = false,
bool KeepExceptions = false,
- bool KeepRounding = false) const {
+ bool KeepRounding = false,
+ bool Strict = false) const {
return Fold(ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW,
- KeepExceptions, KeepRounding));
+ KeepExceptions, KeepRounding, Strict));
}
Constant *CreateFMul(Constant *LHS, Constant *RHS,
bool KeepExceptions = false,
- bool KeepRounding = false) const {
- return Fold(ConstantExpr::getFMul(LHS, RHS, KeepExceptions, KeepRounding));
+ bool KeepRounding = false,
+ bool Strict = false) const {
+ return Fold(ConstantExpr::getFMul(LHS, RHS, KeepExceptions, KeepRounding,
+ Strict));
}
Constant *CreateUDiv(Constant *LHS, Constant *RHS, bool isExact = false)const{
return Fold(ConstantExpr::getUDiv(LHS, RHS, isExact));
@@ -85,8 +92,10 @@ public:
}
Constant *CreateFDiv(Constant *LHS, Constant *RHS,
bool KeepExceptions = false,
- bool KeepRounding = false) const {
- return Fold(ConstantExpr::getFDiv(LHS, RHS, KeepExceptions, KeepRounding));
+ bool KeepRounding = false,
+ bool Strict = false) const {
+ return Fold(ConstantExpr::getFDiv(LHS, RHS, KeepExceptions, KeepRounding,
+ Strict));
}
Constant *CreateURem(Constant *LHS, Constant *RHS) const {
return Fold(ConstantExpr::getURem(LHS, RHS));
@@ -96,8 +105,10 @@ public:
}
Constant *CreateFRem(Constant *LHS, Constant *RHS,
bool KeepExceptions = false,
- bool KeepRounding = false) const {
- return Fold(ConstantExpr::getFRem(LHS, RHS, KeepExceptions, KeepRounding));
+ bool KeepRounding = false,
+ bool Strict = false) const {
+ return Fold(ConstantExpr::getFRem(LHS, RHS, KeepExceptions, KeepRounding,
+ Strict));
}
Constant *CreateShl(Constant *LHS, Constant *RHS,
bool HasNUW = false, bool HasNSW = false) const {
diff --git a/include/llvm/IR/ConstantFolder.h b/include/llvm/IR/ConstantFolder.h
index d7f8e01..3f9ec66 100644
--- a/include/llvm/IR/ConstantFolder.h
+++ b/include/llvm/IR/ConstantFolder.h
@@ -37,8 +37,10 @@ public:
}
Constant *CreateFAdd(Constant *LHS, Constant *RHS,
bool KeepExceptions = false,
- bool KeepRounding = false) const {
- return ConstantExpr::getFAdd(LHS, RHS, KeepExceptions, KeepRounding);
+ bool KeepRounding = false,
+ bool Strict = false) const {
+ return ConstantExpr::getFAdd(LHS, RHS, KeepExceptions, KeepRounding,
+ Strict);
}
Constant *CreateSub(Constant *LHS, Constant *RHS,
bool HasNUW = false, bool HasNSW = false) const {
@@ -46,20 +48,25 @@ public:
}
Constant *CreateFSub(Constant *LHS, Constant *RHS,
bool KeepExceptions = false,
- bool KeepRounding = false) const {
- return ConstantExpr::getFSub(LHS, RHS, KeepExceptions, KeepRounding);
+ bool KeepRounding = false,
+ bool Strict = false) const {
+ return ConstantExpr::getFSub(LHS, RHS, KeepExceptions, KeepRounding,
+ Strict);
}
Constant *CreateMul(Constant *LHS, Constant *RHS,
bool HasNUW = false, bool HasNSW = false,
bool KeepExceptions = false,
- bool KeepRounding = false) const {
+ bool KeepRounding = false,
+ bool Strict = false) const {
return ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW, KeepExceptions,
- KeepRounding);
+ KeepRounding, Strict);
}
Constant *CreateFMul(Constant *LHS, Constant *RHS,
bool KeepExceptions = false,
- bool KeepRounding = false) const {
- return ConstantExpr::getFMul(LHS, RHS, KeepExceptions, KeepRounding);
+ bool KeepRounding = false,
+ bool Strict = false) const {
+ return ConstantExpr::getFMul(LHS, RHS, KeepExceptions, KeepRounding,
+ Strict);
}
Constant *CreateUDiv(Constant *LHS, Constant *RHS,
bool isExact = false) const {
@@ -71,8 +78,10 @@ public:
}
Constant *CreateFDiv(Constant *LHS, Constant *RHS,
bool KeepExceptions = false,
- bool KeepRounding = false) const {
- return ConstantExpr::getFDiv(LHS, RHS, KeepExceptions, KeepRounding);
+ bool KeepRounding = false,
+ bool Strict = false) const {
+ return ConstantExpr::getFDiv(LHS, RHS, KeepExceptions, KeepRounding,
+ Strict);
}
Constant *CreateURem(Constant *LHS, Constant *RHS) const {
return ConstantExpr::getURem(LHS, RHS);
@@ -82,8 +91,10 @@ public:
}
Constant *CreateFRem(Constant *LHS, Constant *RHS,
bool KeepExceptions = false,
- bool KeepRounding = false) const {
- return ConstantExpr::getFRem(LHS, RHS, KeepExceptions, KeepRounding);
+ bool KeepRounding = false,
+ bool Strict = false) const {
+ return ConstantExpr::getFRem(LHS, RHS, KeepExceptions, KeepRounding,
+ Strict);
}
Constant *CreateShl(Constant *LHS, Constant *RHS,
bool HasNUW = false, bool HasNSW = false) const {
diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h
index db487d2..f5ae2c9 100644
--- a/include/llvm/IR/Constants.h
+++ b/include/llvm/IR/Constants.h
@@ -865,29 +865,35 @@ public:
bool HasNUW = false, bool HasNSW = false);
static Constant *getFAdd(Constant *C1, Constant *C2,
bool KeepExceptions = false,
- bool KeepRounding = false);
+ bool KeepRounding = false,
+ bool Strict = false);
static Constant *getSub(Constant *C1, Constant *C2,
bool HasNUW = false, bool HasNSW = false);
static Constant *getFSub(Constant *C1, Constant *C2,
bool KeepExceptions = false,
- bool KeepRounding = false);
+ bool KeepRounding = false,
+ bool Strict = false);
static Constant *getMul(Constant *C1, Constant *C2,
bool HasNUW = false, bool HasNSW = false,
bool KeepExceptions = false,
- bool KeepRounding = false);
+ bool KeepRounding = false,
+ bool Strict = false);
static Constant *getFMul(Constant *C1, Constant *C2,
bool KeepExceptions = false,
- bool KeepRounding = false);
+ bool KeepRounding = false,
+ bool Strict = false);
static Constant *getUDiv(Constant *C1, Constant *C2, bool isExact = false);
static Constant *getSDiv(Constant *C1, Constant *C2, bool isExact = false);
static Constant *getFDiv(Constant *C1, Constant *C2,
bool KeepExceptions = false,
- bool KeepRounding = false);
+ bool KeepRounding = false,
+ bool Strict = false);
static Constant *getURem(Constant *C1, Constant *C2);
static Constant *getSRem(Constant *C1, Constant *C2);
static Constant *getFRem(Constant *C1, Constant *C2,
bool KeepExceptions = false,
- bool KeepRounding = false);
+ bool KeepRounding = false,
+ bool Strict = false);
static Constant *getAnd(Constant *C1, Constant *C2);
static Constant *getOr(Constant *C1, Constant *C2);
static Constant *getXor(Constant *C1, Constant *C2);
diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp
index 4277f7d..b8dc0e1 100644
--- a/lib/IR/Constants.cpp
+++ b/lib/IR/Constants.cpp
@@ -2260,9 +2260,10 @@ Constant *ConstantExpr::getAdd(Constant *C1, Constant *C2,
}
Constant *ConstantExpr::getFAdd(Constant *C1, Constant *C2,
- bool KeepExceptions, bool KeepRounding) {
+ bool KeepExceptions, bool KeepRounding,
+ bool Strict) {
return get(Instruction::FAdd, C1, C2, 0, nullptr, KeepExceptions,
- KeepRounding);
+ KeepRounding, Strict);
}
Constant *ConstantExpr::getSub(Constant *C1, Constant *C2,
@@ -2273,24 +2274,27 @@ Constant *ConstantExpr::getSub(Constant *C1, Constant *C2,
}
Constant *ConstantExpr::getFSub(Constant *C1, Constant *C2,
- bool KeepExceptions, bool KeepRounding) {
+ bool KeepExceptions, bool KeepRounding,
+ bool Strict) {
return get(Instruction::FSub, C1, C2, 0, nullptr, KeepExceptions,
- KeepRounding);
+ KeepRounding, Strict);
}
Constant *ConstantExpr::getMul(Constant *C1, Constant *C2,
bool HasNUW, bool HasNSW,
- bool KeepExceptions, bool KeepRounding) {
+ bool KeepExceptions, bool KeepRounding,
+ bool Strict) {
unsigned Flags = (HasNUW ? OverflowingBinaryOperator::NoUnsignedWrap : 0) |
(HasNSW ? OverflowingBinaryOperator::NoSignedWrap : 0);
return get(Instruction::Mul, C1, C2, Flags, nullptr, KeepExceptions,
- KeepRounding);
+ KeepRounding, Strict);
}
Constant *ConstantExpr::getFMul(Constant *C1, Constant *C2,
- bool KeepExceptions, bool KeepRounding) {
+ bool KeepExceptions, bool KeepRounding,
+ bool Strict) {
return get(Instruction::FMul, C1, C2, 0, nullptr, KeepExceptions,
- KeepRounding);
+ KeepRounding, Strict);
}
Constant *ConstantExpr::getUDiv(Constant *C1, Constant *C2, bool isExact) {
@@ -2304,9 +2308,10 @@ Constant *ConstantExpr::getSDiv(Constant *C1, Constant *C2, bool isExact) {
}
Constant *ConstantExpr::getFDiv(Constant *C1, Constant *C2,
- bool KeepExceptions, bool KeepRounding) {
+ bool KeepExceptions, bool KeepRounding,
+ bool Strict) {
return get(Instruction::FDiv, C1, C2, 0, nullptr, KeepExceptions,
- KeepRounding);
+ KeepRounding, Strict);
}
Constant *ConstantExpr::getURem(Constant *C1, Constant *C2) {
@@ -2318,9 +2323,10 @@ Constant *ConstantExpr::getSRem(Constant *C1, Constant *C2) {
}
Constant *ConstantExpr::getFRem(Constant *C1, Constant *C2,
- bool KeepExceptions, bool KeepRounding) {
+ bool KeepExceptions, bool KeepRounding,
+ bool Strict) {
return get(Instruction::FRem, C1, C2, 0, nullptr, KeepExceptions,
- KeepRounding);
+ KeepRounding, Strict);
}
Constant *ConstantExpr::getAnd(Constant *C1, Constant *C2) {
--
2.3.5
-------------- next part --------------
>From 803a078e1891cf556eba7d8733706ff122d95da9 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 12 Dec 2014 16:40:08 +0200
Subject: [PATCH 10/13] Use Strict in IRBuilder
Try to create constant expression, but skip it in case of conflicts
with FPEnv access flags.
---
include/llvm/IR/IRBuilder.h | 25 +++++++++++++++----------
unittests/IR/IRBuilderTest.cpp | 41 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 56 insertions(+), 10 deletions(-)
diff --git a/include/llvm/IR/IRBuilder.h b/include/llvm/IR/IRBuilder.h
index 43089d4..2be4686 100644
--- a/include/llvm/IR/IRBuilder.h
+++ b/include/llvm/IR/IRBuilder.h
@@ -737,8 +737,9 @@ public:
bool KeepExceptions = false, bool KeepRounding = false) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
- return Insert(Folder.CreateFAdd(LC, RC, KeepExceptions, KeepRounding),
- Name);
+ if (Constant *C = Folder.CreateFAdd(LC, RC, KeepExceptions,
+ KeepRounding, true))
+ return Insert(C, Name);
return Insert(AddFPMathAttributes(BinaryOperator::CreateFAdd(LHS, RHS),
FPMathTag, FMF), Name);
}
@@ -761,8 +762,9 @@ public:
bool KeepExceptions = false, bool KeepRounding = false) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
- return Insert(Folder.CreateFSub(LC, RC, KeepExceptions, KeepRounding),
- Name);
+ if (Constant *C = Folder.CreateFSub(LC, RC, KeepExceptions,
+ KeepRounding, true))
+ return Insert(C, Name);
return Insert(AddFPMathAttributes(BinaryOperator::CreateFSub(LHS, RHS),
FPMathTag, FMF), Name);
}
@@ -785,8 +787,9 @@ public:
bool KeepExceptions = false, bool KeepRounding = false) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
- return Insert(Folder.CreateFMul(LC, RC, KeepExceptions, KeepRounding),
- Name);
+ if (Constant *C = Folder.CreateFMul(LC, RC, KeepExceptions,
+ KeepRounding, true))
+ return Insert(C, Name);
return Insert(AddFPMathAttributes(BinaryOperator::CreateFMul(LHS, RHS),
FPMathTag, FMF), Name);
}
@@ -819,8 +822,9 @@ public:
bool KeepExceptions = false, bool KeepRounding = false) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
- return Insert(Folder.CreateFDiv(LC, RC, KeepExceptions, KeepRounding),
- Name);
+ if (Constant *C = Folder.CreateFDiv(LC, RC, KeepExceptions,
+ KeepRounding, true))
+ return Insert(C, Name);
return Insert(AddFPMathAttributes(BinaryOperator::CreateFDiv(LHS, RHS),
FPMathTag, FMF), Name);
}
@@ -841,8 +845,9 @@ public:
bool KeepExceptions = false, bool KeepRounding = false) {
if (Constant *LC = dyn_cast<Constant>(LHS))
if (Constant *RC = dyn_cast<Constant>(RHS))
- return Insert(Folder.CreateFRem(LC, RC, KeepExceptions, KeepRounding),
- Name);
+ if (Constant *C = Folder.CreateFRem(LC, RC, KeepExceptions,
+ KeepRounding, true))
+ return Insert(C, Name);
return Insert(AddFPMathAttributes(BinaryOperator::CreateFRem(LHS, RHS),
FPMathTag, FMF), Name);
}
diff --git a/unittests/IR/IRBuilderTest.cpp b/unittests/IR/IRBuilderTest.cpp
index e8aaaea..ea3d081 100644
--- a/unittests/IR/IRBuilderTest.cpp
+++ b/unittests/IR/IRBuilderTest.cpp
@@ -204,6 +204,47 @@ TEST_F(IRBuilderTest, FastMathFlags) {
}
+TEST_F(IRBuilderTest, FPEnvFlags) {
+ IRBuilder<> Builder(BB);
+ Value *F;
+
+ Constant *Huge = ConstantFP::get(Type::getDoubleTy(Ctx), 1.000000e+308);
+ Constant *Big = ConstantFP::get(Type::getDoubleTy(Ctx), 1.000000e+300);
+ Constant *Small = ConstantFP::get(Type::getDoubleTy(Ctx), 1.000000e-300);
+ Constant *Tiny = ConstantFP::get(Type::getDoubleTy(Ctx), 1.000000e-308);
+ Constant *Zero = ConstantFP::get(Type::getDoubleTy(Ctx), 0.0);
+
+ F = Builder.CreateFAdd(Huge, Huge, "", nullptr, /* KeepExceptions */ true);
+ EXPECT_FALSE(isa<Constant>(F));
+
+ F = Builder.CreateFSub(Tiny, Huge, "", nullptr, /* KeepExceptions */ true);
+ EXPECT_FALSE(isa<Constant>(F));
+
+ F = Builder.CreateFMul(Big, Big, "", nullptr, /* KeepExceptions */ true);
+ EXPECT_FALSE(isa<Constant>(F));
+
+ F = Builder.CreateFDiv(Big, Small, "", nullptr, /* KeepExceptions */ true);
+ EXPECT_FALSE(isa<Constant>(F));
+
+ F = Builder.CreateFDiv(Big, Zero, "", nullptr, /* KeepExceptions */ true);
+ EXPECT_FALSE(isa<Constant>(F));
+
+ F = Builder.CreateFRem(Big, Zero, "", nullptr, /* KeepExceptions */ true);
+ EXPECT_FALSE(isa<Constant>(F));
+
+ F = Builder.CreateFAdd(Huge, Huge, "", nullptr, /* KeepExceptions */ false,
+ /* KeepRounding */ true);
+ EXPECT_FALSE(isa<Constant>(F));
+
+ F = Builder.CreateFSub(Tiny, Huge, "", nullptr, /* KeepExceptions */ false,
+ /* KeepRounding */ true);
+ EXPECT_FALSE(isa<Constant>(F));
+
+ F = Builder.CreateFMul(Huge, Huge, "", nullptr, /* KeepExceptions */ false,
+ /* KeepRounding */ true);
+ EXPECT_FALSE(isa<Constant>(F));
+}
+
TEST_F(IRBuilderTest, WrapFlags) {
IRBuilder<true, NoFolder> Builder(BB);
--
2.3.5
-------------- next part --------------
>From 16d8d4f54d70dcbd3071073e4a78665f9f5b8bc9 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Mon, 15 Dec 2014 14:18:03 +0200
Subject: [PATCH 11/13] Don't convert fpops to constexprs in SCCP
---
lib/Transforms/Scalar/SCCP.cpp | 18 ++++++++++++----
.../SCCP/do-not-convert-fpop-to-constexpr.ll | 24 ++++++++++++++++++++++
2 files changed, 38 insertions(+), 4 deletions(-)
create mode 100644 test/Transforms/SCCP/do-not-convert-fpop-to-constexpr.ll
diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp
index bc068f7..a1f3cae 100644
--- a/lib/Transforms/Scalar/SCCP.cpp
+++ b/lib/Transforms/Scalar/SCCP.cpp
@@ -851,10 +851,20 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
LatticeVal &IV = ValueState[&I];
if (IV.isOverdefined()) return;
- if (V1State.isConstant() && V2State.isConstant())
- return markConstant(IV, &I,
- ConstantExpr::get(I.getOpcode(), V1State.getConstant(),
- V2State.getConstant()));
+ if (V1State.isConstant() && V2State.isConstant()) {
+ bool KeepExceptions = false;
+ bool KeepRounding = false;
+
+ if (isa<FPMathOperator>(&I)) {
+ KeepExceptions = I.hasKeepExceptions();
+ KeepRounding = I.hasKeepRounding();
+ }
+
+ if (Constant *C = ConstantExpr::get(I.getOpcode(), V1State.getConstant(),
+ V2State.getConstant(), 0, nullptr,
+ KeepExceptions, KeepRounding, true))
+ return markConstant(IV, &I, C);
+ }
// If something is undef, wait for it to resolve.
if (!V1State.isOverdefined() && !V2State.isOverdefined())
diff --git a/test/Transforms/SCCP/do-not-convert-fpop-to-constexpr.ll b/test/Transforms/SCCP/do-not-convert-fpop-to-constexpr.ll
new file mode 100644
index 0000000..df3275a
--- /dev/null
+++ b/test/Transforms/SCCP/do-not-convert-fpop-to-constexpr.ll
@@ -0,0 +1,24 @@
+; fmuls shouldn't be converted to constant expressions.
+; RUN: opt < %s -sccp -S -enable-except-access-fp-math | FileCheck %s
+
+define double @do-not-convert-fpop-to-constexpr(double %x) {
+; CHECK-LABEL: @do-not-convert-fpop-to-constexpr(
+; CHECK: fmul
+; CHECK: fmul
+; CHECK-NOT: select
+entry:
+ %cmp = fcmp oeq double %x, 0.000000e+00
+ br i1 %cmp, label %cond.true, label %cond.false
+
+cond.true:
+ %val.true = fmul kexc double 1.000000e+300, 1.000000e+300
+ br label %cond.end
+
+cond.false:
+ %val.false = fmul kexc double 1.000000e-300, 1.000000e-300
+ br label %cond.end
+
+cond.end:
+ %cond = phi double [ %val.true, %cond.true ], [ %val.false, %cond.false ]
+ ret double %cond
+}
--
2.3.5
-------------- next part --------------
>From 27e9d885d176bb1800ab24e775050ef6eb7921d2 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 19 Dec 2014 15:08:59 +0200
Subject: [PATCH 12/13] Prevent InstCombine from hanging
InstCombine shouldn't hang in non-terminating sequence of conversions like:
(a + b) => (a - (-b)) => (a + b) => etc.
---
lib/Transforms/InstCombine/InstCombineAddSub.cpp | 27 +++++++-------
test/Other/fpenv-constant-fold.ll | 9 ++---
.../do-not-hand-on-fpops-with-fpenv-access.ll | 42 ++++++++++++++++++++++
3 files changed, 62 insertions(+), 16 deletions(-)
create mode 100644 test/Transforms/InstCombine/do-not-hand-on-fpops-with-fpenv-access.ll
diff --git a/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index a8d0172..0faa56c 100644
--- a/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1333,22 +1333,25 @@ Instruction *InstCombiner::visitFAdd(BinaryOperator &I) {
return NV;
}
- // -A + B --> B - A
- // -A + -B --> -(A + B)
- if (Value *LHSV = dyn_castFNegVal(LHS)) {
- Instruction *RI = BinaryOperator::CreateFSub(RHS, LHSV);
- RI->copyFastMathFlags(&I);
- return RI;
- }
-
- // A + -B --> A - B
- if (!isa<Constant>(RHS))
- if (Value *V = dyn_castFNegVal(RHS)) {
- Instruction *RI = BinaryOperator::CreateFSub(LHS, V);
+ // Skip this to break implicit infinite loop with "fsub" transformations.
+ if (!I.hasKeepExceptions() && !I.hasKeepRounding()) {
+ // -A + B --> B - A
+ // -A + -B --> -(A + B)
+ if (Value *LHSV = dyn_castFNegVal(LHS)) {
+ Instruction *RI = BinaryOperator::CreateFSub(RHS, LHSV);
RI->copyFastMathFlags(&I);
return RI;
}
+ // A + -B --> A - B
+ if (!isa<Constant>(RHS))
+ if (Value *V = dyn_castFNegVal(RHS)) {
+ Instruction *RI = BinaryOperator::CreateFSub(LHS, V);
+ RI->copyFastMathFlags(&I);
+ return RI;
+ }
+ }
+
// Check for (fadd double (sitofp x), y), see if we can merge this into an
// integer add followed by a promotion.
if (SIToFPInst *LHSConv = dyn_cast<SIToFPInst>(LHS)) {
diff --git a/test/Other/fpenv-constant-fold.ll b/test/Other/fpenv-constant-fold.ll
index 01dbfa0..68b94ca 100644
--- a/test/Other/fpenv-constant-fold.ll
+++ b/test/Other/fpenv-constant-fold.ll
@@ -1,4 +1,5 @@
-; InstCombine is used just for its calls to constant folder.
+; InstCombine is used just for its calls to constant folder, it is the cause of
+; fsub -> fadd transformation.
; RUN: opt -S -instcombine -o - < %s | FileCheck %s
; Target independent constant folder should not fold floating-point operations
@@ -15,7 +16,7 @@ entry:
define double @do-not-fold-fsub-that-can-trap() {
; CHECK-LABEL: @do-not-fold-fsub-that-can-trap
-; CHECK: fsub
+; CHECK: fadd
entry:
%val = fsub kexc double 1.000000e-308, 1.000000e+308
ret double %val
@@ -55,7 +56,7 @@ entry:
define double @do-not-fold-fsub-because-of-rounding() {
; CHECK-LABEL: @do-not-fold-fsub-because-of-rounding
-; CHECK: fsub
+; CHECK: fadd
entry:
%val = fsub kround double 0.101, 0.93
ret double %val
@@ -92,7 +93,7 @@ define double @fold-fsub-that-cant-trap() {
; CHECK-LABEL: @fold-fsub-that-cant-trap
; CHECK-NOT: fsub
entry:
- %val = fsub kexc kround double 1.0, 1.0
+ %val = fadd kexc kround double 1.0, 1.0
ret double %val
}
diff --git a/test/Transforms/InstCombine/do-not-hand-on-fpops-with-fpenv-access.ll b/test/Transforms/InstCombine/do-not-hand-on-fpops-with-fpenv-access.ll
new file mode 100644
index 0000000..8ea33f0
--- /dev/null
+++ b/test/Transforms/InstCombine/do-not-hand-on-fpops-with-fpenv-access.ll
@@ -0,0 +1,42 @@
+; RUN: opt < %s -instcombine -S
+
+; InstCombine shouldn't hang in non-terminating sequence of conversions like:
+; (a + b) => (a - (-b)) => (a + b) => etc.
+
+define double @test1() {
+entry:
+ %add = fadd kexc double 0x3FF921FB54442D18, 0x3870000000000000
+ ret double %add
+}
+
+define double @test2(double %x) {
+entry:
+ %sub = fsub kexc kround double -0.000000e+00, 1.000000e+00
+ %div = fdiv kexc kround double %sub, %x
+ ret double %div
+}
+
+define double @test3() {
+entry:
+ %sub = fsub kexc kround double -0.000000e+00, 0x400921FB54442D18
+ ret double %sub
+}
+
+define double @test4(i32 %y) {
+entry:
+ %tobool = icmp ne i32 %y, 0
+ br i1 %tobool, label %cond.true, label %cond.false
+
+cond.true:
+ %sub = fsub kexc kround double -0.000000e+00, 0x400921FB54442D18
+ %div = fdiv kexc kround double %sub, 2.000000e+00
+ br label %cond.end
+
+cond.false:
+ %div1 = fdiv kexc kround double 0x400921FB54442D18, 2.000000e+00
+ br label %cond.end
+
+cond.end:
+ %cond = phi double [ %div, %cond.true ], [ %div1, %cond.false ]
+ ret double %cond
+}
--
2.3.5
-------------- next part --------------
>From 874ec7e6913e5e310b9608e0f880456b6765a6f0 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Mon, 2 Feb 2015 18:53:43 +0200
Subject: [PATCH 13/13] Don't hoist FP-ops with side-effects in LICM
---
lib/Transforms/Scalar/LICM.cpp | 4 ++++
test/Transforms/LICM/fpenv.ll | 30 ++++++++++++++++++++++++++++++
2 files changed, 34 insertions(+)
create mode 100644 test/Transforms/LICM/fpenv.ll
diff --git a/lib/Transforms/Scalar/LICM.cpp b/lib/Transforms/Scalar/LICM.cpp
index f0e6d64..af13591 100644
--- a/lib/Transforms/Scalar/LICM.cpp
+++ b/lib/Transforms/Scalar/LICM.cpp
@@ -489,6 +489,10 @@ bool canSinkOrHoistInst(Instruction &I, AliasAnalysis *AA, DominatorTree *DT,
!isa<InsertValueInst>(I))
return false;
+ if (const FPMathOperator *MathOp = dyn_cast<FPMathOperator>(&I))
+ if (MathOp->hasKeepExceptions() || MathOp->hasKeepRounding())
+ return false;
+
// TODO: Plumb the context instruction through to make hoisting and sinking
// more powerful. Hoisting of loads already works due to the special casing
// above.
diff --git a/test/Transforms/LICM/fpenv.ll b/test/Transforms/LICM/fpenv.ll
new file mode 100644
index 0000000..6fb459c
--- /dev/null
+++ b/test/Transforms/LICM/fpenv.ll
@@ -0,0 +1,30 @@
+; RUN: opt < %s -O3 -S | FileCheck %s
+
+define void @fdiv-is-not-hoisted-out-of-loop(i32 %n) {
+; CHECK-LABEL: @fdiv-is-not-hoisted-out-of-loop(
+; CHECK: for.body:
+; CHECK: fdiv
+entry:
+ %cmp2 = icmp sgt i32 %n, 0
+ br i1 %cmp2, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:
+ %0 = add i32 %n, -1
+ br label %for.body
+
+for.body:
+ %i.03 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]
+ %div = fdiv kexc kround double 0.000000e+00, 0.000000e+00
+ tail call void @process(double %div)
+ %inc = add nuw nsw i32 %i.03, 1
+ %exitcond = icmp eq i32 %i.03, %0
+ br i1 %exitcond, label %for.end.loopexit, label %for.body
+
+for.end.loopexit:
+ br label %for.end
+
+for.end:
+ ret void
+}
+
+declare void @process(double) nounwind
--
2.3.5
More information about the llvm-commits
mailing list