-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Implementation of '#pragma STDC FENV_ROUND' #89617
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,7 @@ | |
#include "clang/CodeGen/CGFunctionInfo.h" | ||
#include "clang/CodeGen/SwiftCallingConv.h" | ||
#include "llvm/ADT/StringExtras.h" | ||
#include "llvm/ADT/StringSet.h" | ||
#include "llvm/Analysis/ValueTracking.h" | ||
#include "llvm/IR/Assumptions.h" | ||
#include "llvm/IR/AttributeMask.h" | ||
|
@@ -5693,6 +5694,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, | |
AllocAlignAttrEmitter AllocAlignAttrEmitter(*this, TargetDecl, CallArgs); | ||
Attrs = AllocAlignAttrEmitter.TryEmitAsCallSiteAttribute(Attrs); | ||
|
||
// Prepare execution environment. | ||
setRoundingModeForCall(Callee); | ||
|
||
// Emit the actual call/invoke instruction. | ||
llvm::CallBase *CI; | ||
if (!InvokeDest) { | ||
|
@@ -5846,6 +5850,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, | |
// lexical order, so deactivate it and run it manually here. | ||
CallArgs.freeArgumentMemory(*this); | ||
|
||
// Restore execution environment. | ||
restoreRoundingModeAfterCall(); | ||
|
||
// Extract the return value. | ||
RValue Ret = [&] { | ||
switch (RetAI.getKind()) { | ||
|
@@ -5980,6 +5987,64 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, | |
return Ret; | ||
} | ||
|
||
static bool endsWithRoundingModeSuffix(StringRef FuncName) { | ||
size_t Underscore = FuncName.find_last_of("_"); | ||
if (Underscore == StringRef::npos || Underscore < 2) | ||
return false; | ||
StringRef Suffix = FuncName.substr(Underscore + 1); | ||
static const StringRef RMSuffixes[] = {"rtz", "rte", "rtp", "rtn", "rhaz", | ||
"rz", "rn", "ru", "rd"}; | ||
for (auto RM : RMSuffixes) { | ||
if (Suffix == RM) | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
bool CodeGenFunction::requiresDynamicRounding(const CGCallee &Callee) { | ||
if (Callee.isOrdinary()) { | ||
const Decl *CalleeDecl = Callee.getAbstractInfo().getCalleeDecl().getDecl(); | ||
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CalleeDecl)) { | ||
IdentifierInfo *FuncNameII = FD->getDeclName().getAsIdentifierInfo(); | ||
if (FuncNameII) { | ||
StringRef FuncName = FuncNameII->getName(); | ||
// If a reserved identifier ends with rounding mode suffix preceded by | ||
// underscore, this function does not need the previous dynamic rounding | ||
// mode to be set. | ||
Comment on lines
+6011
to
+6013
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is this rule coming from? |
||
if (isReservedInAllContexts( | ||
FuncNameII->isReserved(getContext().getLangOpts()))) { | ||
if (endsWithRoundingModeSuffix(FuncName)) | ||
return false; | ||
} | ||
} | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
/// Sets dynamic rounding mode for the function called in the region where | ||
/// pragma FENV_ROUND is in effect. | ||
void CodeGenFunction::setRoundingModeForCall(const CGCallee &Callee) { | ||
if (Target.hasStaticRounding() || Callee.isBuiltin() || | ||
!requiresDynamicRounding(Callee)) | ||
return; | ||
if (!CurrentRoundingIsStatic || !DynamicRoundingMode) | ||
return; | ||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::set_rounding), | ||
DynamicRoundingMode); | ||
CurrentRoundingIsStatic = false; | ||
Comment on lines
+6028
to
+6035
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not seeing logic here to effect the proper handling of, e.g., |
||
} | ||
|
||
void CodeGenFunction::restoreRoundingModeAfterCall() { | ||
if (Target.hasStaticRounding() || CurFPFeatures.isRoundingModeDynamic()) | ||
return; | ||
if (CurrentRoundingIsStatic || !StaticRoundingMode) | ||
return; | ||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::set_rounding), | ||
StaticRoundingMode); | ||
CurrentRoundingIsStatic = true; | ||
} | ||
|
||
CGCallee CGCallee::prepareConcreteCallee(CodeGenFunction &CGF) const { | ||
if (isVirtual()) { | ||
const CallExpr *CE = getVirtualCallExpr(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we actually have any (non-target-specific) IR constructs at the moment that actually implement static rounding mode. The documentation for constrained intrinsics says:
It's also the case that static rounding mode may be a less-than-global decision. X86 AVX512/AVX10 has static rounding mode, which is a subtarget consideration, but even then, it's not entirely clear that they would be absolutely preferred.