Kaylor, Andrew via llvm-dev
2017-Nov-27 20:12 UTC
[llvm-dev] clarification needed for the constrained fp implementation.
Hi Brian,
I was just cleaning up my inbox and saw that I had never responded to your
e-mail below. I apologize for that. It was not intentional. Did the subsequent
discussion answer your questions?
In any event, let me address your specific question about the language
reference, where it says "These intrinsics are used to provide special
handling of floating point operations when specific rounding mode or floating
point exception behavior is required" (your emphasis repeated for
discussion). The idea here was that these intrinsics can be used to control the
behavior of the optimizer, in order to allow non-default rounding mode and
floating point exception behavior. The "required" behavior must be
expressed in the IR, as always, but the intrinsics only perform the operation
they are documented to perform. I suppose I should clean up the language
reference to make this less ambiguous.
It's unclear to me whether your processor supports directly encoding the
rounding mode into floating point instructions. If it does not, then I don't
see how having the semantics of the intrinsics force a given rounding mode would
help, as the generated code would still require instructions that explicitly set
the rounding mode before (and possibly after) each floating point instruction.
If your processor does allow the rounding mode to be encoded in an instruction,
then I can understand the desire to have a way to encode that into the IR, but
for the IR to remain target-independent we would still need to support targets
that do not have this capability. My earlier suggestion of intrinsics to
establish a "local" rounding mode was intended to enable this sort of
model.
Regarding your question about having to save and restore the rounding mode when
calling a function, I think that depends on the language-specific semantics of
the function you are calling. The C99 standard, for instance, requires that
functions not change the rounding mode unless they are specifically documented
as doing so and that any function called is assumed to require the default
rounding mode unless it is specifically documented otherwise. (The FENV_ACCESS
pragma can provide a sort of "documentation" for locally defined
functions in this regard.) So, basically, it's up to the front end (or
whatever other mechanism generates your IR) to ensure that the necessary
conventions are correctly followed.
Does that help?
Thanks,
Andy
From: Sumner, Brian [mailto:Brian.Sumner at amd.com]
Sent: Friday, November 03, 2017 1:54 PM
To: Kaylor, Andrew <andrew.kaylor at intel.com>; Ding, Wei <Wei.Ding2
at amd.com>; Arsenault, Matthew <Matthew.Arsenault at amd.com>
Cc: LLVM Developers Mailing List (llvmdev at cs.uiuc.edu) <llvmdev at
cs.uiuc.edu>
Subject: RE: clarification needed for the constrained fp implementation.
Hi Andy,
I'm having some trouble correlating your comments with the LLVM language
reference manual which says: "These intrinsics are used to provide special
handling of floating point operations when specific rounding mode or floating
point exception behavior is required." (Emphasis added by me.) We believed
that this meant that we could use these intrinsics when we required our target
to generate a floating point operation with a specific rounding mode. We have
been attempting to implement these semantics, which are somewhat different than
"a way of telling the optimizer what it can and cannot assume about
rounding mode and FP exception behavior".
We had hoped to avoid defining target specific intrinsics to request FP
operations with specific rounding, and we prefer to attach the desired rounding
to each specific operation. The approach using something like
llvm.get.roundingmode() and llvm.set.roundingmode() is not nearly as appealing
to us. For example, suppose we have library functions that require the default
(to-nearest-even) rounding to achieve correct behavior. Must we now start
saving and restoring the rounding mode in every such function to protect it from
a higher level caller possibly changing the rounding mode?
In short, I would prefer to continue to follow the semantics stated in the
manual, and would be happy to see the ".experimental" dropped as well.
Thanks,
Brian
From: Kaylor, Andrew [mailto:andrew.kaylor at intel.com]
Sent: Friday, November 03, 2017 1:11 PM
To: Ding, Wei; Sumner, Brian; Arsenault, Matthew
Cc: LLVM Developers Mailing List (llvmdev at cs.uiuc.edu<mailto:llvmdev at
cs.uiuc.edu>)
Subject: RE: clarification needed for the constrained fp implementation.
Hi Wei,
I've been meaning to write something up for discussion on the LLVM Dev list
about this. I hope you don't mind if I copy the list now to accomplish that
while also answering your questions. Eventually I create a document describing
this in more detail and less formally than the language definition.
Basically, the "constraints" in the constrained FP intrinisics are
constraints on the optimizer. They are a way of telling the optimizer what it
can and cannot assume about rounding mode and FP exception behavior. By
default, the optimizer assumes that the rounding mode is round-to-nearest and
that FP exceptions are being ignored. If the user code is going to do anything
that invalidates these assumptions, then we need a way to make the optimizer
stop assuming that. That's what the intrinisics do. Because most passes
don't recognize the intrinisics, they can't do anything with the
operations they represent and therefore can't make any assumption about
them.
The intrinsics are not intended to do anything to change the rounding mode or FP
exception handling state. I have an idea in mind for some additional intrinsics
that would provide a way to control the FP environment. There are already some
target-specific mechanisms for doing that, but I'd like to have something
that's target independent. I'll say more about this in a minute.
I mentioned in my review comments that my work on this has been motivated by the
STDC pragmas, and I think if I explain that it might make the semantics of the
intrinsics seem a little more natural. The primary pragma I have in mind here
is the "STDC FENV_ACCESS" pragma. I believe this is part of the C99
standard, but compiler support for it is still mostly (if not entirely) missing.
For instance, if you try to use this pragma with clang you will get a message
telling you that the pragma isn't supported and it will have no other
effect. We want to change that.
Basically, what the "STDC FENV_ACCESS" pragma does is provide
programmers with a way to tell the compiler that the program might change the FP
environment. This pragma represents a setting that has only two states -- on
and off. The default setting of this state is documented as being
implementation defined. In clang the default state will be off. The C99
standard states that accessing the FP environment (testing FP status flags,
changing FP control modes, etc.) when FENV_ACCESS is off is undefined behavior.
The C99 standard provides library calls to access the environment (fesetround,
fegetround, fetestexcept, etc.) but you can only safely use these if you have
set FENV_ACCESS to the "on" state. A typical usage might look like
this:
#include <fenv.h>
double someFunc(double A, double B, bool ForceRoundUp) {
#pragma STDC FENV_ACCESS ON
double Result;
if (ForceRoundUp) {
int OldRM = fegetround();
fesetround(FE_UPWARD);
Result = A/B;
fesetround(OldRM);
} else {
Result = A/B;
}
return Result;
}
So you see here that there are explicit calls to change the rounding mode. If
you were to do this in clang today, the generated IR would look like this:
define double @someFunc(double, double, i1) {
br i1 %2, label %4, label %8
; <label>:4: ; preds = %3
%5 = tail call i32 @fegetround()
%6 = tail call i32 @fesetround(i32 2048)
%7 = tail call i32 @fesetround(i32 %5)
br label %8
; <label>:8: ; preds = %3, %4
%9 = fdiv double %0, %1
ret double %9
}
Notice that the fdiv got sunk outside of the calls to change the rounding mode.
Once we support the FENV_ACCESS pragma, the generated IR will look like this
instead:
define double @someFunc(double, double, i1) {
br i1 %2, label %4, label %8
; <label>:4: ; preds = %3
%5 = tail call i32 @fegetround()
%6 = tail call i32 @fesetround(i32 2048)
%7 = call double llvm.experimental.constrained.fdiv.f64(double %0, double%1,
metadata "round.dynamic", metadata "fpexcept.strict")
%8 = tail call i32 @fesetround(i32 %5)
br label %11
; <label>:9: ; preds = %3
%10 = call double llvm.experimental.constrained.fdiv.f64(double %0, double%1,
metadata "round.dynamic", metadata "fpexcept.strict")
Br label %11
; <label>:11: ; preds = %4, %9
%12 = phi double [ %7, %4 ], [ %10, %9 ]
ret double %12
}
Note that I've left the rounding mode as "round.dynamic" here. In
theory we could implement an optimization that recognizes the calls to
fesetround and changes that argument to "round.upward", but initially
it will be "round.dynamic" which indicates that the program is allowed
to change the rounding mode at runtime and that's what I expect will always
come out of the front end.
The key point here is that the pragma just gives the programmer permission to
change things. There are some other pragmas in draft standards that allow the
programmer to specify what the rounding mode will be for a given scope, but it
is my understanding that they do not actually change the rounding mode either.
They just tell the compiler what the programmer is promising the rounding mode
will be at that point.
All of this is substantially background information with regard to LLVM since
the LLVM optimizer is independent of any front end. The key point I'm
trying to convey is that the constrained intrinsics are meant to behave in a way
that is analogous to these pragmas.
What I think we need now are a set of language-neutral and target-independent
intrinsics that allow us to control the FP rounding mode. For instance, suppose
you are implementing some function and you want to be able to control the
rounding mode for the entire scope of the function. You typically will need to
do that similarly to what I showed in my example above -- get the current
rounding mode, set the rounding mode, perform some operations, and restore the
rounding mode. I don't think you would want the constrained intrinsics that
we have to be responsible for controlling the rounding mode because that would
mean that the backend would need to generate instructions to get-set-restore the
rounding mode around every operation in your function (unless the target
supports explicit rounding mode operands).
What I'm thinking is that we need something like this:
void llvm.set.roundingmode(i32 mode)
i32 lllvm.get.roundingmode()
These would then get translated during instruction selection to target-specific
instructions, which is equivalent to what fesetround() and fegetround() do. But
I think it would also be useful to have something like this:
void llvm.begin.local.roundingmode(i32 mode)
void llvm.end.local.roundingmode()
This could encapsulate to get-set-restore idiom. My thinking then is that if a
target does support explicit rounding mode operands, these intrinsics
wouldn't need to result in any instructions that change the processors
rounding mode and could instead just be used to determine what the rounding mode
operand should be where applicable.
There are still some issues that need to be worked out here (such as the fact
that a i32 here is far too general), but that's basically what I'm
thinking.
Does that make sense?
-Andy
From: Ding, Wei [mailto:Wei.Ding2 at amd.com]
Sent: Friday, November 03, 2017 12:04 PM
To: Kaylor, Andrew <andrew.kaylor at intel.com<mailto:andrew.kaylor at
intel.com>>; Sumner, Brian <Brian.Sumner at
amd.com<mailto:Brian.Sumner at amd.com>>; Arsenault, Matthew
<Matthew.Arsenault at amd.com<mailto:Matthew.Arsenault at amd.com>>
Subject: clarification needed for the constrained fp implementation.
Hi Andy,
Thanks a lot for your comments https://reviews.llvm.org/D38634. Actually, I
don't think I got 100% clear about the way you are trying to implement for
the constrained fps. If possible, could you please elaborate on? Especially I
don't quite follow your comments like "I'm approaching this from
the perspective of the STDC pragmas related to the FP environment. ".
Thank you so much!
Best regards,
Wei
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20171127/f406b125/attachment.html>